[bzoj3531][Sdoi2014]旅行
S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
n<=10^5
正确题解:对每种颜色都把关于这种颜色的操作全部存下来之后一起做,线段树上查,很简单很愉快
然后我讲讲我做这道题的艰难历程。
看到题目,yy了一会儿,树剖,然后每种颜色一棵平衡树,没毛病。
开始打代码,打什么平衡树呢?splay常数好像有点大,treap不熟练,算了就替罪羊吧。
轻松打完替罪羊,又看了看题目,哇居然要查最值!!!替罪羊怎么查啊?打了六七十行不想重打了,还好yy了一个类似线段树那样的查法,没毛病,但是效率就不太行了。
交一发,wa!然后开始对拍,改错。终于根本拍不出错了,交洛谷,a啦!然后交bzoj,心想终于a了,结果wa
???????我就懵逼,不知道怎么wa的只好找学长要数据,先放着呗。
然后第二天,感谢善良的学长拿到数据啦!测一发,woc只过了几个点,手测,fc一下,找不到差异.....赶紧找来ditoly看看看
然后发现一开O2就挂,不开就能a,心想玄学了。找了好久,最后发现,写函数 没 ! re !turn ! 貌似不开o2自动返回最后一句话的值...加了一句话A了,感觉自己是个假人.....
不说了,代码8000B,SGT的操作都快要全了,都是泪。
线段树做法大家自己yy吧,我对这题失去兴趣了
#include<iostream> #include<cstdio> #include<cstdlib> #define getc() (*S++) #define int long long using namespace std; char B[1<<25],*S=B; inline int read() { int x = 0 , f = 1; char ch = getc(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getc();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getc();} return x * f; } namespace SGT { #define MN 400000 int fa[MN+5],cnt=0,c[MN+5][2],size[MN+5],nn[MN+5],rt[MN+5],mark=0,top=0,q[MN+5],s[MN+5],num[MN+5],mx[MN+5]; bool b[MN+5]; int tms=0; inline void update(int x) { int l=c[x][0],r=c[x][1]; size[x]=size[l]+size[r]+b[x]; s[x]=s[l]+s[r]+(b[x]?num[x]:0); mx[x]=max(mx[l],mx[r]); if(b[x]) mx[x]=max(mx[x],num[x]); } void ins(int&x,int rk,int n,int last) { if(!x){ x=++cnt;fa[x]=last;num[x]=n;s[x]=n;mx[x]=n; size[x]=1;nn[x]=rk;b[x]=1; return; } if(nn[x]==rk) { b[x]=1;fa[x]=last;num[x]=n;s[x]=n;mx[x]=n; size[x]=1;nn[x]=rk;update(x);return; } ins(c[x][rk>nn[x]],rk,n,x);update(x); if(max(size[c[x][1]],size[c[x][0]])>0.7*size[x]) mark=x; } void del(int x,int k) { if(nn[x]==k&&b[x]) {b[x]=0;update(x);return;} del(c[x][nn[x]<k],k);update(x); } int query(int x,int rk) { if(!x) return 0; if(nn[x]>rk) return query(c[x][0],rk); else return query(c[x][1],rk)+(b[x]?num[x]:0)+s[c[x][0]]; } void dfs(int x) { if(c[x][0]) dfs(c[x][0]); if(b[x])q[++top]=x; if(c[x][1]) dfs(c[x][1]); } void build(int&x,int l,int r,int last) { if(l>r){x=0;return;} int mid=l+r>>1;x=q[mid];fa[x]=last; build(c[x][0],l,mid-1,x); build(c[x][1],mid+1,r,x); update(x); } void rebuild(int num) { int y=fa[mark];top=0;dfs(mark); if(!y)build(rt[num],1,top,0); else build(c[y][c[y][1]==mark],1,top,y); mark=0; } int aska(int x,int k) { if(!x) return 0; if(k>=nn[x]) return size[c[x][0]]+b[x]+aska(c[x][1],k); return aska(c[x][0],k); } int askb(int x,int k) { if(!x) return 0; if(k>nn[x]) return askb(c[x][1],k); return size[c[x][1]]+b[x]+askb(c[x][0],k); } int GetMax(int x,int l,int r,int lt,int rt) { if(!x||l>r||!r)return 0; if(l==lt&&r==rt)return mx[x]; if(b[x]) { int mid=size[c[x][0]]+lt; if(r<mid) return GetMax(c[x][0],l,r,lt,mid-1); else if(l>mid) return GetMax(c[x][1],l,r,mid+1,rt); else { int mx=max(GetMax(c[x][0],l,mid-1,lt,mid-1),GetMax(c[x][1],mid+1,r,mid+1,rt)); if(l<=mid&&mid<=r) mx=max(mx,num[x]); return mx; } } else { int mid=size[c[x][0]]+lt-1; if(r<=mid) return GetMax(c[x][0],l,r,lt,mid); else if(l>mid) return GetMax(c[x][1],l,r,mid+1,rt); else return max(GetMax(c[x][0],l,mid,lt,mid),GetMax(c[x][1],mid+1,r,mid+1,rt)); } } int getmax(int x,int l,int r) { int lt=aska(rt[x],l-1)+1;int rl=size[rt[x]]-askb(rt[x],r+1); lt=max(lt,1LL);rl=min(rl,size[rt[x]]);if(lt>rl)return 0; return GetMax(rt[x],lt,rl,1,size[rt[x]]); } void modify(int x,int k,int ad) { if(nn[x]==k&&b[x]) {num[x]=ad;update(x);return;} modify(c[x][k>nn[x]],k,ad);update(x); } #undef MN } namespace TREE { #define MN 200000 struct edge{int to,next;}e[MN*2+5]; int fa[MN+5],top[MN+5],size[MN+5],mx[MN+5],cnt=0,head[MN+5],nl[MN+5],nr[MN+5],dfn=0,dep[MN+5]; void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void dfs1(int x,int f) { fa[x]=f;size[x]=1; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) { dep[e[i].to]=dep[x]+1;dfs1(e[i].to,x);size[x]+=size[e[i].to]; if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to; } } void dfs2(int x,int tp) { nl[x]=++dfn;top[x]=tp; if(mx[x]) dfs2(mx[x],tp); for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa[x]&&e[i].to!=mx[x]) dfs2(e[i].to,e[i].to); nr[x]=dfn; } #undef MN } #define MN 200000 int n,m,s[MN+5],kind[MN+5]; char op; void solve_sum(int x,int y) { using namespace TREE; int sum=0,k=kind[x]; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); sum+=SGT::query(SGT::rt[k],nl[x])-SGT::query(SGT::rt[k],nl[top[x]]-1); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); sum+=SGT::query(SGT::rt[k],nl[x]);sum-=SGT::query(SGT::rt[k],nl[y]-1); printf("%d\n",sum); } void solve_max(int x,int y) { using namespace TREE; int mx=0,k=kind[x]; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); mx=max(mx,SGT::getmax(k,nl[top[x]],nl[x])); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); mx=max(mx,SGT::getmax(k,nl[y],nl[x])); printf("%d\n",mx); } main() { fread(B,1,1<<25,stdin); n=read();m=read(); for(int i=1;i<=n;i++) s[i]=read(),kind[i]=read(); for(int i=1;i<n;i++) { int u=read(),v=read(); TREE::ins(u,v); } TREE::dfs1(1,0);TREE::dfs2(1,1); for(int i=1;i<=n;i++) { SGT::ins(SGT::rt[kind[i]],TREE::nl[i],s[i],0); if(SGT::mark) SGT::rebuild(kind[i]); } for(int i=1;i<=m;i++) { do op=getc(); while(op<'A'||op>'Z'); op=getc();int l=read(),r=read(); if(op=='S') solve_sum(l,r); if(op=='M') solve_max(l,r); if(op=='C') { if(kind[l]==r) continue; SGT::del(SGT::rt[kind[l]],TREE::nl[l]);SGT::ins(SGT::rt[kind[l]=r],TREE::nl[l],s[l],0); if(SGT::mark) SGT::rebuild(kind[l]); } if(op=='W') SGT::modify(SGT::rt[kind[l]],TREE::nl[l],s[l]=r); } return 0; }