10
4
2018
1

[UOJ15] 【NOIP2014】生活大爆炸版石头剪刀布

练一下python

以下代码在python2.7编译通过

这个题直接做,循环就可以了

win=[[1, 0, 2, 2, 0], [2, 1, 0, 2, 0], [0, 2, 1, 0, 2], [0, 0, 2, 1, 2], [2, 2, 0, 0, 1]]
xiaoa=[]; xiaob=[]; wina=0; winb=0
n, na, nb=map(int, raw_input().split())
#print n, na, nb
p=raw_input().split()
for i in range(0, na):
    xiaoa.append(int(p[i]))
p=raw_input().split()
for i in range(0, nb):
    xiaob.append(int(p[i]))
for i in range(0, n):
    px=win[int(xiaoa[i%na])][int(xiaob[i%nb])]
    if px==0:
        winb+=1
    elif px==2:
        wina+=1
print wina, winb
Category: 其他OJ | Tags: uoj
10
17
2016
1

UOJ Easy Round #7 题解

毛爷爷已经发过了:链接

我来写一些考试时的感受吧

开考后6min:

T1什么鬼?但是好像不难……

T2什么鬼?答案可以有误差?

T3什么鬼?我只会暴力

开考后10min:

T1没思路啊……弃疗比赛算了

开考后1hr46min:

啊!UOJ比赛不是CF,只要看了题目都计入排行榜!赶快写题不然Rating要掉了!

开考后2hr17min:

哎……T1为啥不是每次向右向下走一格呢?啊!原来走中间时间最短的越长越好而不是直接在当前走!

开考后2hr37min:

提交T1,赶快写T2暴力吧

开考后2hr52min:

T2暴力写完了赶快写T3暴力

开考后3hr3min:

啊!T3暴力刚写完!弃疗算了

最终得分100+50+0

-------------------------

以下为部分题解

A.短路

考虑每个环要么走一格要么走完全部,否则将多余的一步用于时间更少的环显然更优

略微推一下式子就发现可以线性扫描一遍解决

时间复杂度$O(n)$

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005;
const long long INF=99999999999999999ll;

int n;
long long a[N],ans,last,sho,lw;

int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d",&n);
for(int i=0;i<=n;i++)scanf("%lld",&a[i]);
last=4ll*a[n];
ans=(n*4ll+1)*a[n];
sho=a[n];lw=n;
for(int i=n-1;i>=0;i--){
	if(a[i]<sho){sho=a[i];lw=i;}
	last+=(sho+a[i])*2ll;
	ans=min(ans,last+i*4ll*a[i]-3*a[i]);
	//printf("Aw:%lld %lld\n",ans,last+i*4ll*a[i]-3*a[i]);
}
printf("%lld\n",ans);
return 0;
}

B.天路

订正时发现题目看错了……是与答案相差$5\%$而不是5!

那么每次乘一下1.05就不会出问题了……然后随便把小于枚举值的ans更新一下即可

复杂度我也不太会分析你萌看毛爷爷的解释吧

那个分治现在还不太会……

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=100005,INF=1000005;

int n,a[N],ans[N],mx[N],mn[N],f1,f2,l1,l2;

inline void Read(int &x){
static char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0';
}

inline int Calc(int x){
mx[f1=l1=1]=1;
mn[f2=l2=1]=1;
int pos=1;
for(register int i=2;i<=n;i++){
	while(f1<=l1 && a[mx[l1]]<a[i])l1--;
	while(f2<=l2 && a[mn[l2]]>a[i])l2--;
	mx[++l1]=i;mn[++l2]=i;
	while(a[mx[f1]]-a[mn[f2]]>x){
		pos++;
		while(f1<=l1 && mx[f1]<pos)f1++;
		while(f2<=l2 && mn[f2]<pos)f2++;
	}
	ans[i-pos+1]=min(ans[i-pos+1],a[mx[f1]]-a[mn[f2]]);
}
}

inline void Solve(){
for(register int i=0;i<=INF*2;i=(int)(i*1.05)+1)Calc(int(i*1.05));
for(register int i=n-1;i>=2;i--)ans[i]=min(ans[i],ans[i+1]);
for(register int i=2;i<=n;i++)printf("%d\n",ans[i]);
}

int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
Read(n);
for(register int i=1;i<=n;i++)Read(a[i]),ans[i]=1e9;
if(n<=1000){
	for(register int i=1;i<=n;i++){
		int mx=a[i],mn=a[i];
		for(register int j=i+1;j<=n;j++){
			mx=max(mx,a[j]);mn=min(mn,a[j]);
			ans[j-i+1]=min(ans[j-i+1],mx-mn);
		}
	}
	for(register int i=2;i<=n;i++)printf("%d\n",ans[i]);
}
else Solve();
return 0;
}
Category: 比赛 | Tags: OI uoj
8
17
2016
0

[UOJ222] 【NOI2016】区间

two points+线段树

按长度排序之后一个个加就行

我考场上居然没想到

数组开小wa了2次……身败名裂

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=500005,INF=1000000000;

int b[N<<1],n,m,cnt,ans=INF,tot;

struct Inside{
int l,r,len;
friend bool operator<(const Inside &A,const Inside &B){return A.len<B.len;}
}ins[N];

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

struct SegTree{
int l,r,tag,cnt;
}tree[N<<3];

inline void Pushup(const int &rt){
tree[rt].cnt=tree[rt].tag+max(tree[rt<<1].cnt,tree[rt<<1|1].cnt);
}

void Build(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;
if(l==r)return;
int mid=l+r>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
}

void Add(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r){tree[rt].cnt++;tree[rt].tag++;return;}
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Add(rt<<1,l,r);
if(r>mid)Add(rt<<1|1,l,r);
Pushup(rt);
}

void Del(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r){tree[rt].cnt--;tree[rt].tag--;return;}
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Del(rt<<1,l,r);
if(r>mid)Del(rt<<1|1,l,r);
Pushup(rt);
}

int main(){
freopen("222.in","r",stdin);
freopen("222.out","w",stdout);
Read(n);Read(m);
for(int i=1;i<=n;i++){
	Read(ins[i].l);Read(ins[i].r);
	ins[i].len=ins[i].r-ins[i].l;
	b[++cnt]=ins[i].l;b[++cnt]=ins[i].r;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=n;i++)ins[i].l=lower_bound(b+1,b+cnt+1,ins[i].l)-b,ins[i].r=lower_bound(b+1,b+cnt+1,ins[i].r)-b;
sort(ins+1,ins+n+1);
Build(1,1,cnt);
int cur=0;
for(int i=1;i<=n;i++){
    while(cur<n && tree[1].cnt<m){cur++;Add(1,ins[cur].l,ins[cur].r);}
    if(tree[1].cnt<m)break;
    ans=min(ans,ins[cur].len-ins[i].len);
    Del(1,ins[i].l,ins[i].r);
}
printf("%d\n",ans==INF?-1:ans);
return 0;
}
Category: 其他OJ | Tags: OI uoj
8
16
2016
0

UOJ Round #15 题解

这次比赛我打的很不好……其实是因为懒

没写暴力

当时做掉了A,BC当时不会做,现在也不会做

所以暂时只有A的题解

A.奥林匹克五子棋

我们思考怎么摆放最优

首先我们发现每一行的摆放是否连通只和上一行的摆放方式有关

所以我们要尽量减少连通

想让上下不联通得左右放

想让左右不联通得上下放

那么我们就得到了一种摆放的方式

0101010101

0101010101

1010101010

1010101010

这样就可以完成目标了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

int n,m,k;
queue<pair<int,int> > Q1,Q2;

int Abs(int x){return x>0?x:-x;}

int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d %d %d",&n,&m,&k);
if(k==1){puts("-1");return 0;}
else if(k==2){if(n<2 || m<2){if(n==1)for(int i=1;i<=m;i++)printf("%d %d\n",1,i);else if(m==1)for(int i=1;i<=n;i++)printf("%d %d\n",i,1);}else puts("-1");return 0;}
else if(k>min(n,m)){
	for(int i=1;i<=n;i++){
        if(i%2){if(m%2)for(int j=1;j<=m;j++)printf("%d %d\n",i,j);else for(int j=m;j;j--)printf("%d %d\n",i,j);}
        else for(int j=1;j<=m;j++)printf("%d %d\n",i,j);
	}
	return 0;
}
else if(k>2){
	for(int i=1;i<=n;i++){
		if(i%4==1 || i%4==2){for(int j=1;j<=m;j++){if(j&1)Q1.push(make_pair(i,j));else Q2.push(make_pair(i,j));}}
		else {for(int j=1;j<=m;j++){if(j&1)Q2.push(make_pair(i,j));else Q1.push(make_pair(i,j));}}
	}
	if(Abs(Q1.size()-Q2.size())>=2){
		while(!Q1.empty())Q1.pop();
		while(!Q2.empty())Q2.pop();
		swap(n,m);
		for(int i=1;i<=n;i++){
			if(i%4==1 || i%4==2){for(int j=1;j<=m;j++){if(j&1)Q1.push(make_pair(j,i));else Q2.push(make_pair(j,i));}}
			else {for(int j=1;j<=m;j++){if(j&1)Q2.push(make_pair(j,i));else Q1.push(make_pair(j,i));}}
		}
		if(Abs(Q1.size()-Q2.size())>=2){puts("-1");return 0;}
		else {
            int x=n*m,flg=1;
			while(x--){
				if(flg){printf("%d %d\n",Q1.front().first,Q1.front().second);Q1.pop();}
				else {printf("%d %d\n",Q2.front().first,Q2.front().second);Q2.pop();}
				flg^=1;
			}
		}
	}
	else {
		int x=n*m,flg=1;
		while(x--){
			if(flg){printf("%d %d\n",Q1.front().first,Q1.front().second);Q1.pop();}
			else {printf("%d %d\n",Q2.front().first,Q2.front().second);Q2.pop();}
			flg^=1;
		}
	}
	return 0;
}
return 0;
}

B.奥林匹克环城马拉松

正在思考中

C.奥林匹克数据结构

正在思考中

 

Category: 比赛 | Tags: 比赛 OI uoj
8
4
2016
0

[UOJ3] 【NOI2014】魔法森林

sbLCT调了这么长时间……

Splay部分写错了

按照a从小到大排序,用LCT维护最小生成树

没了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=50005,INF=1000000000;

int n,m,ans=INF;

struct Node{
int v,id;
bool rev;
Node *ch[2],*fa,*mxe;
Node();
void Pushdown();
void Pushup();
}*tree[N<<2],*Null;

struct Ed{
int u,v,a,b;
friend bool operator<(const Ed &A,const Ed &B){return A.a<B.a||(A.a==B.a && A.b<B.b);}
}es[N<<1];

Node::Node(){fa=ch[0]=ch[1]=Null;mxe=this;v=-INF;rev=id=0;}

inline void Node::Pushdown(){
if(rev){
	if(ch[0]!=Null)ch[0]->rev^=1;
	if(ch[1]!=Null)ch[1]->rev^=1;
    swap(ch[0],ch[1]);
    rev=0;
}
}

inline void Node::Pushup(){
mxe=this;
if(ch[0]->mxe->v>mxe->v)mxe=ch[0]->mxe;
if(ch[1]->mxe->v>mxe->v)mxe=ch[1]->mxe;
}

inline bool Notroot(Node *x){return x->fa->ch[0]==x || x->fa->ch[1]==x;}
inline void Prepare(Node *x){if(Notroot(x))Prepare(x->fa);x->Pushdown();}

void Rotate(Node *x,int kind){
Node *y=x->fa,*z=y->fa;
y->ch[!kind]=x->ch[kind];
if(x->ch[kind]!=Null)x->ch[kind]->fa=y;
x->fa=z;
if(Notroot(y))z->ch[z->ch[1]==y]=x;
y->fa=x;
x->ch[kind]=y;
y->Pushup();
x->Pushup();
}

void Splay(Node *x){
Prepare(x);
while(Notroot(x)){
	Node *y=x->fa,*z=y->fa;
    if(!Notroot(y))Rotate(x,y->ch[0]==x);
    else {
        if(y->ch[0]==x && z->ch[0]==y){Rotate(y,1);Rotate(x,1);}
        else if(y->ch[0]==x && z->ch[1]==y){Rotate(x,1);Rotate(x,0);}
        else if(y->ch[1]==x && z->ch[0]==y){Rotate(x,0);Rotate(x,1);}
        else {Rotate(y,0);Rotate(x,0);}
    }
}
}

void Access(Node *x){for(Node *y=Null;x!=Null;y=x,x=x->fa){Splay(x);x->ch[1]=y;x->Pushup();}}
void Makeroot(Node *x){Access(x);Splay(x);x->rev^=1;}
void Link(Node *x,Node *y){Makeroot(x);x->fa=y;}
void Cut(Node *x,Node *y){Makeroot(x);Access(y);Splay(y);y->ch[0]=x->fa=Null;y->Pushup();}
Node *Find(Node *x){Access(x);Splay(x);while(x->ch[0]!=Null)x=x->ch[0];return x;}
Node *GetNull(){Node *p=new Node();p->ch[0]=p->ch[1]=p->fa=p->mxe=p;return p;}
Node *Query(Node *x,Node *y){Makeroot(x);Access(y);Splay(y);return y->mxe;}

int main(){
freopen("3.in","r",stdin);
freopen("3.out","w",stdout);
scanf("%d %d",&n,&m);
Null=GetNull();
for(int i=1;i<=m;i++)scanf("%d %d %d %d",&es[i].u,&es[i].v,&es[i].a,&es[i].b);
sort(es+1,es+m+1);
for(int i=1;i<=n;i++)tree[i]=new Node();
for(int i=1;i<=m;i++)tree[i+n]=new Node(),tree[i+n]->v=es[i].b,tree[i+n]->id=i;
for(int i=1;i<=m;i++){
    if(es[i].u==es[i].v)continue;
	if(Find(tree[es[i].u])==Find(tree[es[i].v])){
		Node *c=Query(tree[es[i].u],tree[es[i].v]);
		if(c->v>es[i].b){Cut(tree[es[c->id].u],c);Cut(tree[es[c->id].v],c);}
		else {if(Find(tree[1])==Find(tree[n]))ans=min(ans,es[i].a+Query(tree[1],tree[n])->v);continue;}
	}
    Link(tree[es[i].u],tree[i+n]);Link(tree[es[i].v],tree[i+n]);
    if(Find(tree[1])==Find(tree[n])){ans=min(ans,es[i].a+Query(tree[1],tree[n])->v);}
}
printf("%d\n",ans==INF?-1:ans);
return 0;
}
Category: 其他OJ | Tags: OI uoj
8
4
2016
0

[UOJ207] 共价大爷游长沙

虽然已经有官方题解了而且写的和我一样……但是我还来写一次题解凑文章数

首先看了一下题目,发现不会做,就去看题解。

题解中说:"用LCT统计子树异或和",我不会啊!

找到myy代码仔细看了一遍,大概也会统计子树异或和了。

首先我们考虑正常的LCT,你直接把两个child的和异或起来的和其实是你Access的那条链上的和。

那么统计子树就要从这里入手。

我们在Access时加上一些操作:如果原先选中的链不为Null,异或之;如果当前的选中的节点不为Null,异或之;

这样为什么就可以统计子树了呢?

(注意题目的性质,我们的子树异或和一定是Access访问过这个子树的全部节点,所以才能这么做)

考虑一开始啥都没有。

然后我们选中了一条链,那么原先的链啥也没有,我们在Pushup的时候就不考虑异或。

但是现在选中的链是存在的,我们异或一下。

那么我们就统计了这一条链。

之后同理

至于为什么要异或s_c,那是因为你在选中时统计了这个,之后Pushup时s_t又统计了一次

所以要还原

然后我们这题可以随机赋权值,每次碰到就异或一下,求解时确认这条边是否唯一存在即可。

代码跑得并不快(6097ms)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=500005;

int n,m,ID,ans,h[N],en,fa[N],val[N],cnt;
pair<int,int> path[N];

inline void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

inline int Abs(const int &x){return x>0?x:-x;}

inline int Rand(){
return (rand()<<16)|rand();
}

struct Edge{
int b,next;
}e[N<<1];

inline void AddEdge(const int &sa,const int &sb){e[++en].b=sb;e[en].next=h[sa];h[sa]=en;}

struct Node{
int v,v_t,s_c,s_t;
bool rev;
Node *ch[2],*fa;
Node();
inline void Pushdown();
inline void Pushup();
}*tree[N],*Null;

Node::Node(){v=v_t=s_c=s_t=rev=0;ch[0]=ch[1]=fa=Null;}

inline void Node::Pushdown(){
if(rev){
    if(ch[0]!=Null)ch[0]->rev^=1;
    if(ch[1]!=Null)ch[1]->rev^=1;
    swap(ch[0]->ch[0],ch[0]->ch[1]);
    swap(ch[1]->ch[0],ch[1]->ch[1]);
	rev=0;
}
}

inline void Node::Pushup(){
s_t=v_t;s_c=v;
if(ch[0]!=Null)s_t^=ch[0]->s_t,s_c^=ch[0]->s_c;
if(ch[1]!=Null)s_t^=ch[1]->s_t,s_c^=ch[1]->s_c;
}

Node *GetNull(){Node *p=new Node();p->fa=p->ch[0]=p->ch[1]=p;return p;}
int Notroot(Node *x){return x->fa->ch[0]==x||x->fa->ch[1]==x;}
void Prepare(Node *x){if(Notroot(x))Prepare(x->fa);x->Pushdown();}

void Rotate(Node *x,int kind){
Node *y=x->fa,*z=y->fa;
y->ch[!kind]=x->ch[kind];
if(x->ch[kind]!=Null)x->ch[kind]->fa=y;
x->fa=z;
if(Notroot(y))z->ch[z->ch[1]==y]=x;
y->fa=x;
x->ch[kind]=y;
y->Pushup();
x->Pushup();
}

void Splay(Node *x){
Prepare(x);
while(Notroot(x)){
	Node *y=x->fa,*z=y->fa;
	if(!Notroot(y))Rotate(x,y->ch[0]==x);
    else {
        if(y->ch[0]==x && z->ch[0]==y){Rotate(y,1);Rotate(x,1);}
		else if(y->ch[0]==x && z->ch[1]==y){Rotate(x,1);Rotate(x,0);}
		else if(y->ch[1]==x && z->ch[0]==y){Rotate(x,0);Rotate(x,1);}
		else {Rotate(y,0);Rotate(x,0);}
    }
}
}

void Access(Node *x){
for(Node *y=Null;x!=Null;y=x,x=x->fa){
	Splay(x);
	if(x->ch[1]!=Null)x->v_t^=x->ch[1]->s_t^x->ch[1]->s_c;
	if(y!=Null)x->v_t^=y->s_t^y->s_c;
	x->ch[1]=y;
    x->Pushup();
}
}

inline void Makeroot(Node *x){
Access(x);
Splay(x);
x->rev^=1;
swap(x->ch[0],x->ch[1]);
}

inline void Link(Node *x,Node *y){
Makeroot(x);
Access(y);
Splay(y);
y->v_t^=x->s_t^x->s_c;
x->fa=y;
Access(x);
}

inline void Cut(Node *x,Node *y){
Makeroot(x);
Access(y);
Splay(y);
x->fa=Null;
y->ch[0]=Null;
x->Pushup();
}

inline void Change(Node *x,int y){Access(x);Splay(x);x->v^=y;x->Pushup();}
inline bool Query(Node *x,Node *y){Makeroot(x);Access(y);Splay(y);/*printf("DEBUG_Q: %d %d %d %d\n",y->v,y->v_t,y->v^y->v_t,ans);*/return (y->v^y->v_t)==ans;}
inline void dfs(int u){for(int i=h[u];i;i=e[i].next){int v=e[i].b;if(v==fa[u])continue;fa[v]=u;dfs(v);}}

int main(){
freopen("207.in","r",stdin);
freopen("207.out","w",stdout);
Read(ID);Read(n);Read(m);
if(ID==11){puts("OrzOrzOrz\nHello,world!\n233666");return 0;}
Null=GetNull();
for(int i=1;i<n;i++){
	int u,v;
    Read(u);Read(v);
	AddEdge(u,v);AddEdge(v,u);
}
dfs(1);
for(int i=1;i<=n;i++)tree[i]=new Node();
for(int i=2;i<=n;i++)tree[i]->fa=tree[fa[i]];
for(int i=0;i<m;i++){
	int opt,u,v,x,y;
    Read(opt);
    if(opt==1){Read(u);Read(v);Read(x);Read(y);Cut(tree[u],tree[v]);Link(tree[x],tree[y]);}
    if(opt==2){Read(x);Read(y);int tp=Rand();ans^=tp;Change(tree[x],tp);Change(tree[y],tp);path[++cnt]=make_pair(x,y);val[cnt]=tp;}
    if(opt==3){Read(x);Change(tree[path[x].first],val[x]);Change(tree[path[x].second],val[x]);ans^=val[x];}
    if(opt==4){Read(x);Read(y);puts(Query(tree[x],tree[y])?"YES":"NO");}
}
return 0;
}
Category: 其他OJ | Tags: OI uoj
4
6
2016
0

[UOJ164] 【清华集训2015】V

最近集训出了很多SGTB(SeGmentTree Beats!)的题目,所以被迫来学习这个冬令营上的黑科技。。

这题照着其他人写的程序理解了几个小时,然后自己写了一发居然是最快的。。。

记录一下自己对于这题的理解吧

输入的操作分别对应:

1.区间加

2.区间max(0,v)

3.区间赋值

4.询问单点值

5.询问单点历史最值

然后我一开始试图维护十来个标记然后暴力搞。。然后就不会了

然后膜了一下其他人的程序和lzz的冬令营课件,总算有了一点理解了

这题关键在于单点询问,所以我们仅仅把区间当成一整个标记,每次下传后就清零

然后问题在于两个操作:询问历史最值和区间max

我们先不管询问历史最值

其实我们进行一番转化后可以发现,其实123操作都可以对应到一个(x,y)(加上x对y取max)上(这是对于一个区间的标记)

1:区间加v -> (v,INF)

2:区间max(0,v) -> (v,0)

3.区间赋值为v -> (-INF,v);

这很显然吧。。

然后我们考虑两个标记的合并,这里我还是想了一下的

设旧标记为A,新标记为B

那么我们进行合并就变成了(A.x+B.x,max(A.y+B.x,B.y))

为什么是这样呢?

首先我们考虑如果A.x+B.x,那么就直接相当于普通线段树的Add操作,明显可行

而max(A.y+B.x,B.y)则表示如果旧标记产生的最大值为A.y,那么我们最终要取的值要么就是旧标记的A.y加上新标记要加上的值(因为旧标记可能取A.y),要么就是新标记要取的B.y(感觉我这句话比较意识流啊),当然是在这两个数里面选一个最大值了

于是我们就处理完了没有历史最值询问的操作

但是这题是有历史最值询问的。。好坑啊

那么我们考虑再加上两个标记mx,addmx表示当前区间的历史最值和要加上去的值的历史最值

那么我们继续考虑合并标记

同样,我们设(X,Y)表示mx和addmx两个值(偷懒),那么我们继续设以前的旧标记为A,用来更新旧标记的新标记为B

那么历史最值可以怎么构成?可以由旧标记的历史最值、新标记的历史最值,或者是旧标记的当前值加上新标记的的历史最大加值。

前两个很好理解,但是最后一个是什么意思呢?

首先,新标记的历史最大加值可以用这样一段话来叙述:“这一段区间曾经加过这么大的值”

那么我们每次拿旧标记当前的值加上新标记的历史最大加值,就意味着这个合并后的标记曾经在某个时刻达到了这个可能的最大值

因为每次更新标记时都是自顶向下,那么没有被更新的旧标记的值一定是当前值,如果被更改了那么之前一定在这里下传过标记,所以这样是对的

而我们再考虑addmx可以怎么构成

显然这个值可能的取值为:旧标记的addmx,新标记的addmx加上旧标记的add

为什么又是这么取值呢?

第一种情况显然。第二种情况因为新标记的历史最大加值此时没有经过任何更新,也就是和旧标记一点关联也没有

而因为add的定义和题目的描述(就是上面的小写标记),add标记一定不会小于0

那么我们当然需要加上这个add值(新标记此前不可能加过add标记),这样能让解更优

那么你可能会问:为什么不能让旧标记的历史最值加上新标记的add呢?

因为新标记是用来更新旧标记的,所以这样可能重复的加所以不行

这仅仅是个人的理解,我觉得真是漏洞百出,具体的证明lzz冬令营课件里面有,反正我没有看太懂。。。

我真是太弱了

这真是一篇意识流的题解

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int n,m;
long long a[500005];
const long long INF=1000000000000000ll;

template<typename T>void Read(T &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}

struct SegTree{
int l,r;
long long v,mx,add,addmx;
SegTree(){}
SegTree(long long V,long long MX,long long ADD,long long ADDMX){v=V;mx=MX;add=ADD;addmx=ADDMX;}
SegTree(int L,int R,long long V,long long MX,long long ADD,long long ADDMX){l=L;r=R;v=V;mx=MX;add=ADD;addmx=ADDMX;}
}tree[2000005],tmp;

SegTree Update(SegTree A,SegTree B){
return SegTree(A.l,A.r,max(A.v+B.add,B.v),max(max(A.mx,B.mx),A.v+B.addmx),max(A.add+B.add,-INF),max(A.addmx,A.add+B.addmx));
}

void Pushdown(int rt){
tree[rt*2]=Update(tree[rt*2],tree[rt]);
tree[rt*2+1]=Update(tree[rt*2+1],tree[rt]);
tree[rt]=SegTree(tree[rt].l,tree[rt].r,0,0,0,0);
}

void Build(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;
if(l==r){
	tree[rt].addmx=tree[rt].add=tree[rt].v=tree[rt].mx=a[l];
	return;
}
int mid=l+r>>1;
Build(rt*2,l,mid);
Build(rt*2+1,mid+1,r);
}

void Change(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r){tree[rt]=Update(tree[rt],tmp);return;}
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Change(rt*2,l,r);
if(r>mid)Change(rt*2+1,l,r);
}

long long Query(int rt,int pos,int id){
if(tree[rt].l==tree[rt].r){return id?tree[rt].mx:tree[rt].v;}
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(pos<=mid)return Query(rt*2,pos,id);
if(pos>mid)return Query(rt*2+1,pos,id);
}

int main(){
freopen("164.in","r",stdin);
freopen("164.out","w",stdout);
Read(n);Read(m);
for(int i=1;i<=n;i++)Read(a[i]);
Build(1,1,n);
for(int i=1;i<=m;i++){
    int opt,l,r,v;
    Read(opt);
    if(opt==1){Read(l);Read(r);Read(v);tmp=SegTree(0,0,v,v);Change(1,l,r);}
    if(opt==2){Read(l);Read(r);Read(v);tmp=SegTree(0,0,-v,-v);Change(1,l,r);}
    if(opt==3){Read(l);Read(r);Read(v);tmp=SegTree(v,v,-INF,-INF);Change(1,l,r);}
    if(opt==4){Read(v);printf("%lld\n",Query(1,v,0));}
    if(opt==5){Read(v);printf("%lld\n",Query(1,v,1));}
}
return 0;
}
Category: 其他OJ | Tags: OI uoj
3
31
2016
0

[UOJ34] 多项式乘法

第一道FFT

话说后缀数组我只会敲模版……这几天的比赛验证了我连暴力都能写挂

但是最近好像碰到好多FFT题目,于是就学习了一下

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;

const double Pi=2*asin(1);
const int NUM_SIZE=100005;

int An,Bn,Cn,Rev[NUM_SIZE*3],Step,n;

struct Complex{
double a,b;
Complex(double as=0.0,double bs=0.0){a=as;b=bs;}
friend Complex operator+(Complex a,Complex b){return Complex(a.a+b.a,a.b+b.b);}
friend Complex operator-(Complex a,Complex b){return Complex(a.a-b.a,a.b-b.b);}
friend Complex operator*(Complex a,Complex b){return Complex(a.a*b.a-a.b*b.b,b.a*a.b+a.a*b.b);}
friend Complex operator/(Complex a,Complex b){return Complex((a.a*b.a+a.b*b.b)/(b.a*b.a+b.b*b.b),(b.a*a.b-a.a*b.b)/(b.a*b.a+b.b*b.b));}
double Mod(){return sqrt(a*a+b*b);}
}A[NUM_SIZE*3],B[NUM_SIZE*3],C[NUM_SIZE*3];

template<typename T>void Read(T &x){
int flag=1;
char ch;
while((ch=getchar())<'0' || ch>'9')if(ch=='-')flag=-1;
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
x*=flag;
}

void FFT(Complex *x,int flag){
for(int i=0;i<n;i++)if(i<Rev[i])swap(x[i],x[Rev[i]]);
for(int k=1;k<n;k<<=1){
    Complex wk=Complex(cos(Pi/k),flag*sin(Pi/k));
    for(int i=0;i<n;i+=k<<1){
		Complex wkj=Complex(1.0,0.0);
		for(int j=0;j<k;j++){
			Complex a=x[i+j],b=x[i+j+k]*wkj;
			x[i+j]=a+b;
			x[i+j+k]=a-b;
			wkj=wkj*wk;
		}
    }
}
if(flag==-1){for(int i=0;i<n;i++)x[i].a/=n;}
}

int main(){
freopen("34.in","r",stdin);
freopen("34.out","w",stdout);
Read(An);Read(Bn);
An++;Bn++;
Cn=An+Bn-1;
for(int i=0;i<An;i++)Read(A[i].a);
for(int i=0;i<Bn;i++)Read(B[i].a);
for(n=1,Step=0;n<Cn;Step++,n<<=1);
for(int i=0;i<n;i++)Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(Step-1));
FFT(A,1);
FFT(B,1);
for(int i=0;i<n;i++)C[i]=A[i]*B[i];
FFT(C,-1);
for(int i=0;i<Cn;i++)printf("%d ",(int)(C[i].a+0.5));
putchar('\n');
return 0;
}
Category: 其他OJ | Tags: OI uoj
3
21
2016
0

[UOJ35] 后缀排序

SA模版,然后我发现我写的SA其实有问题……

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

char s[500005];
int n,rank[500005],rank2[500005],height[500005],sa[500005],rmq[500005][20],ws[500005],wv[500005],er[20],log2[500005];

int cmp(int *r,int a,int b,int l){return (r[a]==r[b])&(r[a+l]==r[b+l]);}

void GetSA(char *r,int *sa,int n,int m){
int i,j,p,*x=rank,*y=rank2,*t;
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[x[i]=r[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--){sa[--ws[x[i]]]=i;}
for(j=p=1;p<n;j*=2,m=p){
	for(p=0,i=n-j;i<n;i++)y[p++]=i;
	for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
	for(i=0;i<m;i++)ws[i]=0;
	for(i=0;i<n;i++)ws[wv[i]=x[y[i]]]++;
	for(i=1;i<m;i++)ws[i]+=ws[i-1];
	for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
	for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}

void CalHeight(char *r,int *sa,int n){
int i,j,k=0;
for(i=1;i<=n;i++)rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}

void RMQ(){
int i,j;
er[0]=1;
for(i=1;i<20;i++)er[i]=er[i-1]<<1;
log2[0]=-1;
for(i=1;i<=n;i++)log2[i]=(i&(i-1))?log2[i-1]:log2[i-1]+1;
for(i=1;i<=n;i++)rmq[i][0]=height[i];
for(j=1;j<20;j++)for(i=1;i+er[j-1]-1<=n;i++)rmq[i][j]=min(rmq[i][j-1],rmq[i+er[j-1]][j-1]);
}

int LCP(int a,int b){
int x=rank[a],y=rank[b],t;
if(x>y)t=x,x=y,y=t;
x++;
int k=log2[y-x+1];
return min(rmq[x][k],rmq[y-er[k]+1][k]);
}

int main(){
scanf("%s",s);
n=strlen(s);
s[n]=0;
GetSA(s,sa,n+1,128);
CalHeight(s,sa,n);
//RMQ();
for(int i=1;i<=n;i++)printf("%d ",sa[i]+1);
putchar('\n');
for(int i=2;i<=n;i++)printf("%d ",height[i]);
return 0;
}
Category: 其他OJ | Tags: OI uoj

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com