3626: [LNOI2014]LCA|动态树
来源:互联网 发布:剑网三重置网络命令 编辑:程序博客网 时间:2024/05/22 10:54
这真是一道神题!!
显然需要离线来解决,再就是用到了差分的思想
以下是PoPoQQQ大爷复制gconeice的题解,说得非常详细,就不再赘述了
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。
动态树都码不对了真是sosad。。。因为一个y打成了x调了1H。。。本来100+行的代码各种输出中间结果成了将近200行?
#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<vector>#include<set>#include<map>#include<iostream>#include<algorithm>#define mod 201314#define ll long long#define N 50005#define mx 1e9using namespace std;int sc(){ int i=0,f=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar(); return i*f;}struct W{int l,z,pos;}a[N*3];ll sum[N],v[N],tag[N],size[N],ans[N*2];int fa[N],ch[N][2],st[N],TI;int n,top,cnt,q;bool rev[N];bool Root(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}bool cmp(W a,W b){return a.l<b.l;}void cal(int x,ll f){ v[x]+=f; tag[x]+=f; sum[x]+=size[x]*f;}void push_up(int x){ sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+v[x]; size[x]=size[ch[x][0]]+size[ch[x][1]]+1;}void push_down(int x){ if(rev[x]) { rev[ch[x][0]]^=1;rev[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]); rev[x]=0; } if(tag[x]) { if(ch[x][0])cal(ch[x][0],tag[x]); if(ch[x][1])cal(ch[x][1],tag[x]); tag[x]=0; }}void rotate(int x){ int y=fa[x],z=fa[y],l,r; l=(ch[y][1]==x);r=l^1; if(!Root(y))ch[z][ch[z][1]==y]=x; ch[y][l]=ch[x][r];ch[x][r]=y; fa[ch[y][l]]=y;fa[y]=x;fa[x]=z; push_up(y),push_up(x);}void splay(int x){ st[top=1]=x; for(int i=x;!Root(i);i=fa[i])st[++top]=fa[i]; while(top)push_down(st[top--]); while(!Root(x)) { int y=fa[x],z=fa[y]; if(!Root(y)) if(ch[y][0]==x^ch[z][0]==y)rotate(x);else rotate(y); rotate(x); }}void access(int x){ for(int t=0;x;t=x,x=fa[x]) splay(x),ch[x][1]=t,push_up(x);}void make_root(int x){ access(x),splay(x),rev[x]^=1;}void link(int x,int y){ make_root(x),fa[x]=y;}void change(int x){ make_root(1),access(x),splay(x); tag[x]+=1;v[x]+=1;sum[x]+=size[x];}ll query(int x){ make_root(1),access(x),splay(x); return sum[x];}int main(){ n=sc(),q=sc(); for(int i=2;i<=n;i++) { int x=sc()+1; if(i!=x)link(x,i); } for(int i=1;i<=q;i++) { int l=sc()+1,r=sc()+1,z=sc()+1; a[++cnt]=(W){l-1,z,2*i-1}; a[++cnt]=(W){r,z,2*i}; } sort(a+1,a+cnt+1,cmp); int now=1; for(int i=1;i<=cnt;i++) { while(now<=a[i].l)change(now),now++; ans[a[i].pos]=query(a[i].z); } for(int i=1;i<=q;i++) printf("%d\n",(ans[2*i]-ans[2*i-1])%mod); return 0;}
附上调了1H的代码。。调不出来的可以借鉴一下各种输出中间结果的姿势。。
#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<vector>#include<set>#include<map>#include<iostream>#include<algorithm>#define mod 201314#define ll long long#define N 50005#define mx 1e9using namespace std;int sc(){ int i=0,f=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar(); return i*f;}struct W{int l,z,pos;}a[N*3];ll sum[N],v[N],tag[N],size[N],ans[N*2];int fa[N],ch[N][2],st[N],TI;int n,top,cnt,q;bool rev[N];bool Root(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}bool cmp(W a,W b){return a.l<b.l;}void cal(int x,ll f){ v[x]+=f; tag[x]+=f; sum[x]+=size[x]*f;}void push_up(int x){ sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+v[x]; size[x]=size[ch[x][0]]+size[ch[x][1]]+1; //cout << x<<" "<< sum[x]<<" "<<ch[x][0]<< " "<<ch[x][1]<<endl;}void push_down(int x){ if(rev[x]) { rev[ch[x][0]]^=1;rev[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]); rev[x]=0; } if(tag[x]) { if(ch[x][0])cal(ch[x][0],tag[x]); if(ch[x][1])cal(ch[x][1],tag[x]); tag[x]=0; }}void rotate(int x){ int y=fa[x],z=fa[y],l,r; l=(ch[y][1]==x);r=l^1; if(!Root(y))ch[z][ch[z][1]==y]=x; ch[y][l]=ch[x][r];ch[x][r]=y; fa[ch[y][l]]=y;fa[y]=x;fa[x]=z; push_up(y),push_up(x);}void splay(int x){ st[top=1]=x; for(int i=x;!Root(i);i=fa[i])st[++top]=fa[i]; while(top)push_down(st[top--]); while(!Root(x)) { //cout<<x<<endl; int y=fa[x],z=fa[y]; if(!Root(y)) if(ch[y][0]==x^ch[z][0]==y)rotate(x);else rotate(y); rotate(x); }}void access(int x){ for(int t=0;x;t=x,x=fa[x]) splay(x),ch[x][1]=t,push_up(x);}void make_root(int x){ access(x),splay(x),rev[x]^=1;}void dfs(int x){ if(!x)return; push_down(x); dfs(ch[x][0]); cout<<x<<endl; dfs(ch[x][1]);}void cacl(){ for(int i=1;i<=5;i++) { if(Root(i)) { printf("ROOT %d\n",i); dfs(i); } }}void link(int x,int y){ //cout << x<<" "<< y<<endl; make_root(x),fa[x]=y; //cacl();}void change(int x){ make_root(1),access(x),splay(x); tag[x]+=1;v[x]+=1;sum[x]+=size[x]; //cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; //if(x==2){dfs(2);system("pause");} //cout<<x<<" "<<sum[x]<<" "<<size[x]<<endl; //system("pause");}ll query(int x){ //TI++;cout<<"TIME "<<TI<<" Query "<<x<<endl; make_root(1),access(x),splay(x); //cout<<x<<" "<<sum[x]<<endl; return sum[x];}void solve(){ int x=1;//system("pause"); make_root(1);access(1);splay(1); dfs(1);tag[x]+=1;v[x]+=1;sum[x]+=size[x]; //cout<<query(4)<<endl<<query(3)<<endl; cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; make_root(1);access(2),splay(2);x=2;dfs(2);tag[x]+=1;v[x]+=1;sum[x]+=size[x]; cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; system("pause");}void solve1(){ int x=1; cacl(); make_root(1),access(x),splay(x); tag[x]+=1;v[x]+=1;sum[x]+=size[x]; cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; cacl(); x=4;make_root(1),access(x),splay(x); cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; cacl(); x=3;make_root(1);cout<<size[1]<<endl; access(x),splay(x); cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; dfs(x); x=2; make_root(1),access(x),splay(x); tag[x]+=1;v[x]+=1;sum[x]+=size[x]; cout<<x<<" "<< size[x]<<" "<<v[x]<<" "<<sum[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<endl; system("pause");}int main(){ n=sc(),q=sc(); for(int i=2;i<=n;i++) { int x=sc()+1; if(i!=x)link(x,i); } for(int i=1;i<=q;i++) { int l=sc()+1,r=sc()+1,z=sc()+1; a[++cnt]=(W){l-1,z,2*i-1}; a[++cnt]=(W){r,z,2*i}; } sort(a+1,a+cnt+1,cmp); //for(int i=1;i<=cnt;i++) cout<<a[i].l<<" "<<a[i].z<<endl;system("pause"); int now=1; for(int i=1;i<=cnt;i++) { while(now<=a[i].l)change(now),now++; ans[a[i].pos]=query(a[i].z); } for(int i=1;i<=q;i++) printf("%d\n",(ans[2*i]-ans[2*i-1])%mod); return 0;}
0 0
- 3626: [LNOI2014]LCA|动态树
- BZOJ[3626][LNOI2014]LCA 树链剖分+线段树
- bzoj 3626: [LNOI2014]LCA
- 【BZOJ 3626】 [LNOI2014]LCA
- [bzoj 3626] LNOI2014 LCA
- 3626: [LNOI2014]LCA LCT
- BZOJ 3626 [LNOI2014]LCA
- 3626: [LNOI2014]LCA
- BZOJ 3626 [LNOI2014]LCA
- BZOJ 3626 [LNOI2014] LCA
- BZOJ 3626 [LNOI2014]LCA
- bzoj 3626 [LNOI2014]LCA
- BZOJ 3626 [LNOI2014]LCA
- bzoj 3626: [LNOI2014]LCA
- bzoj 3626: [LNOI2014]LCA 树链剖分
- bzoj 3626: [LNOI2014]LCA 树链剖分
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
- 【BZOJ3626】 [LNOI2014]LCA
- IT人员应该怎么跳槽
- 关于 App 程序员泡沫
- Oracle数据库恢复误删除数据的方法
- ytu 1330: 数字密码发生器
- Java 征途:行者的地图
- 3626: [LNOI2014]LCA|动态树
- 设置自定义控件view(自定义相对布局和对话框)
- Canal+Otter - Canal篇(1)
- 《基于MFC的OpenGL编程》Part 15 Reflection
- C#使用linq to xml完成对XML文件的创建、增加、删除、修改、查询
- Android Studio 的使用[转]
- js中会使用到的一种表单遍历验证的方法,访问当前节点的兄弟节点
- ytu 1338: 制作表格
- (android实战)Service 生命周期和使用注意项