我又开新坑啦:QTREE系列.
刚开始以为QTREE就是LCT,然后发现第一题是个树链剖分,于是以为QTREE就是树链剖分.写完后发现第二题是个树上倍增.
综上,QTREE就是树上询问的一些题.
来源:http://172.20.6.3/Categories.asp?page=11&order=ASC&channel=ID&c=8
#include<iostream> #include<iomanip> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<string> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<deque> #include<set> #include<bitset> using namespace std; char buf[1<<15],*fs,*ft; inline char getc(){ return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++; } inline int read(){ int This=0,F=1; char ch=getc(); while(ch<'0'||ch>'9'){ if(ch=='-') F=-1; ch=getc(); } while(ch>='0'&&ch<='9'){ This=(This<<1)+(This<<3)+ch-'0'; ch=getc(); } return This*F; } inline void write(int x){ if(x==0){ putchar('0'); return; } if(x<0){ putchar('-'); x=-x; } int num=0;char ch[16]; while(x) ch[++num]=x%10+'0',x/=10; while(num) putchar(ch[num--]); } int siz[10010],top[10010],son[10010],fa[10010],dfn[10010],tot,head[10010],d[10010],fav[10010]; int n,maxx[40010]; struct edge { int x,y,next,v; }e[30000],o[10010]; inline void add(int x,int y,int v) { tot++; e[tot]=(edge){x,y,head[x],v}; head[x]=tot; } inline void change(int now,int l,int r,int x,int v) { if(l==r) { maxx[now]=v; return ; } int mid=l+r>>1; if(x<=mid) change(now<<1,l,mid,x,v); else change(now<<1|1,mid+1,r,x,v); maxx[now]=max(maxx[now<<1],maxx[now<<1|1]); } inline void dfs1(int x) { siz[x]=1; for(int i=head[x];i;i=e[i].next) { if(e[i].y==fa[x]) continue; d[e[i].y]=d[x]+1; fa[e[i].y]=x; dfs1(e[i].y); siz[x]+=siz[e[i].y]; if(siz[e[i].y]>siz[son[x]]) son[x]=e[i].y; } } inline void dfs2(int x) { tot++; dfn[x]=tot; if(!son[x]) return ; top[son[x]]=top[x]; dfs2(son[x]); for(int i=head[x];i;i=e[i].next) { if(e[i].y==fa[x]) continue; else if(e[i].y==son[x]) change(1,1,n,dfn[son[x]],e[i].v); else { top[e[i].y]=e[i].y; fav[e[i].y]=e[i].v; dfs2(e[i].y); } } } inline int ask(int now,int l,int r,int tl,int tr) { if(tl<=l&&r<=tr) return maxx[now]; int mid=l+r>>1,ans=0; if(tl<=mid) ans=max(ans,ask(now<<1,l,mid,tl,tr)); if(tr>mid) ans=max(ans,ask(now<<1|1,mid+1,r,tl,tr)); return ans; } inline int query(int x,int y) { if(x==y) return 0; int fx=top[x],fy=top[y],ans=0; while(fx!=fy) { if(d[fx]>=d[fy]) { ans=max(ans,ask(1,1,n,dfn[fx]+1,dfn[x])); ans=max(ans,fav[fx]); x=fa[fx]; fx=top[x]; } else { ans=max(ans,ask(1,1,n,dfn[fy]+1,dfn[y])); ans=max(ans,fav[fy]); y=fa[fy]; fy=top[y]; } } if(x!=y) { if(d[x]<d[y]) ans=max(ans,ask(1,1,n,dfn[x]+1,dfn[y])); else ans=max(ans,ask(1,1,n,dfn[y]+1,dfn[x])); } return ans; } inline void gai(int nod,int v) { int x=o[nod].x,y=o[nod].y; if(d[x]>d[y]) swap(x,y); if(son[x]==y) change(1,1,n,dfn[y],v); else fav[y]=v; } inline void check(int now,int l,int r) { cout<<l<<' '<<r<<' '<<maxx[now]<<endl; if(l==r) return ; int mid=l+r>>1; check(now<<1,l,mid); check(now<<1|1,mid+1,r); } int main() { //freopen("123.in","r",stdin); //freopen("123.out","w",stdout); int __size__ = 20 << 20; // 20MB char *__p__ = (char*)malloc(__size__) + __size__; __asm__("movl %0, %%esp " :: "r"(__p__)); for(int T=read();T;T--) { n=read(); memset(head,0,sizeof(head)); memset(siz,0,sizeof(siz)); memset(top,0,sizeof(top)); memset(son,0,sizeof(son)); memset(fa,0,sizeof(fa)); memset(dfn,0,sizeof(dfn)); memset(d,0,sizeof(d)); memset(fav,0,sizeof(fav)); memset(maxx,0,sizeof(maxx)); tot=0; for(int i=1;i<n;i++) { o[i].x=read();o[i].y=read();int w=read(); add(o[i].x,o[i].y,w); add(o[i].y,o[i].x,w); } tot=0; dfs1(1); top[1]=1; dfs2(1); while(1) { char ch=getc(); while(ch!='Q'&&ch!='C'&&ch!='D') ch=getc(); if(ch=='Q') { int tx=read();int ty=read(); cout<<query(tx,ty)<<endl; } else if(ch=='C') { int tot=read();int tv=read(); gai(tot,tv); } else break; } }/* for(int i=1;i<=n;i++) { cout<<i<<' '<<fav[i]<<endl; }*/ //check(1,1,n); }
#include<iostream> #include<iomanip> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<string> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<deque> #include<set> #include<bitset> using namespace std; char buf[1<<15],*fs,*ft; inline char getc(){ return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++; } inline int read(){ int This=0,F=1; char ch=getc(); while(ch<'0'||ch>'9'){ if(ch=='-') F=-1; ch=getc(); } while(ch>='0'&&ch<='9'){ This=(This<<1)+(This<<3)+ch-'0'; ch=getc(); } return This*F; } inline void write(int x){ if(x==0){ putchar('0'); return; } if(x<0){ putchar('-'); x=-x; } int num=0;char ch[16]; while(x) ch[++num]=x%10+'0',x/=10; while(num) putchar(ch[num--]); } int n,d[10010],fa[10010][20],c[10010][20],head[10010],tot; struct edge { int y,next,v; }e[20010]; inline void add(int x,int y,int v) { tot++; e[tot]=(edge){y,head[x],v}; head[x]=tot; } inline int get_sum(int x,int y) { int sum=0; if(d[x]>d[y]) swap(x,y); for(int t=15;t>=0;t--) { if(d[fa[y][t]]>=d[x]) sum+=c[y][t],y=fa[y][t]; } if(x==y) return sum; for(int t=15;t>=0;t--) { if(fa[x][t]!=fa[y][t]) sum+=c[x][t]+c[y][t],x=fa[x][t],y=fa[y][t]; } return sum+c[x][0]+c[y][0]; } inline int get_lca(int x,int y) { if(d[x]>d[y]) swap(x,y); for(int t=15;t>=0;t--) { if(d[fa[y][t]]>=d[x]) y=fa[y][t]; } if(x==y) return x; for(int t=15;t>=0;t--) { if(fa[x][t]!=fa[y][t]) x=fa[x][t],y=fa[y][t]; } return fa[x][0]; } inline int get_by_k(int x,int k) { for(int t=15;t>=0;t--) { if((1<<t)<=k) x=fa[x][t],k-=(1<<t); } return x; } stack<int>q; int main() { //freopen("123.in","r",stdin); //freopen("123.out","w",stdout); for(int T=read();T;T--) { memset(d,0,sizeof(d)); memset(head,0,sizeof(head)); tot=0; //fa,c n=read(); for(int i=1;i<n;i++) { int tx=read(),ty=read(),tv=read(); add(tx,ty,tv); add(ty,tx,tv); } q.push(1);d[1]=1; while(q.size()) { int x=q.top();q.pop(); for(int i=head[x];i;i=e[i].next) { if(d[e[i].y]) continue; d[e[i].y]=d[x]+1; fa[e[i].y][0]=x; c[e[i].y][0]=e[i].v; q.push(e[i].y); } } for(int t=1;t<=15;t++) { for(int i=1;i<=n;i++) { fa[i][t]=fa[fa[i][t-1]][t-1]; c[i][t]=c[i][t-1]+c[fa[i][t-1]][t-1]; } } while(1) { char ch=getc(); while(ch!='D'&&ch!='K') ch=getc(); if(ch=='D') { ch=getc(); if(ch=='I') cout<<get_sum(read(),read())<<endl; else break; } else { int x=read();int y=read();int k=read(); int lca=get_lca(x,y); if(d[x]-d[lca]+1>=k) cout<<get_by_k(x,k-1); else cout<<get_by_k(y,d[y]+d[x]-d[lca]-k+1-d[lca]); cout<<endl; } } } }
#include<iostream> #include<iomanip> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<string> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #include<deque> #include<set> #include<bitset> using namespace std; char buf[1<<15],*fs,*ft; inline char getc(){ return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++; } inline int read(){ int This=0,F=1; char ch=getc(); while(ch<'0'||ch>'9'){ if(ch=='-') F=-1; ch=getc(); } while(ch>='0'&&ch<='9'){ This=(This<<1)+(This<<3)+ch-'0'; ch=getc(); } return This*F; } inline void write(int x){ if(x==0){ putchar('0'); return; } if(x<0){ putchar('-'); x=-x; } int num=0;char ch[16]; while(x) ch[++num]=x%10+'0',x/=10; while(num) putchar(ch[num--]); } int n,head[100010],tot,dfn[100010],top[100010],fa[100010],siz[100010],son[100010],a[400010],num[100010]; struct edge { int y,next; }e[200010]; void add(int x,int y) { tot++; e[tot]=(edge){y,head[x]}; head[x]=tot; } void dfs1(int x) { siz[x]=1; for(int i=head[x];i;i=e[i].next) { if(e[i].y==fa[x]) continue; //d[e[i].y]=d[x]+1; fa[e[i].y]=x; dfs1(e[i].y); siz[x]+=siz[e[i].y]; if(siz[e[i].y]>siz[son[x]]) son[x]=e[i].y; } } void dfs2(int x) { tot++; dfn[x]=tot; num[tot]=x; if(!son[x]) return ; top[son[x]]=top[x]; dfs2(son[x]); for(int i=head[x];i;i=e[i].next) { if(e[i].y==fa[x]||e[i].y==son[x])continue; top[e[i].y]=e[i].y; dfs2(e[i].y); } } int ask(int now,int l,int r,int tl,int tr) { if(tl<=l&&r<=tr) return a[now]; int mid=l+r>>1,t=0; if(tl<=mid) { t=ask(now<<1,l,mid,tl,tr); if(t) return t; } if(tr>mid) return ask(now<<1|1,mid+1,r,tl,tr); else return 0; } int query(int x) { int fx=top[x],ans=0,t=0; while(fx!=1) { t=ask(1,1,n,dfn[fx],dfn[x]); if(t)//一旦有,那就是 ans=t; x=fa[fx]; fx=top[x]; } t=ask(1,1,n,dfn[1],dfn[x]); if(t) return t; else return ans; } void change(int now,int l,int r,int x) { if(l==r) { a[now]=x-a[now]; return ; } int mid=l+r>>1; if(x<=mid) change(now<<1,l,mid,x); else change(now<<1|1,mid+1,r,x); a[now]=a[now<<1]?a[now<<1]:a[now<<1|1]; }/* void check(int now,int l,int r) { cout<<l<<' '<<r<<' '<<a[now]<<endl; if(l==r) return ; int mid=l+r>>1; check(now<<1,l,mid); check(now<<1|1,mid+1,r); }*/ int main() { //freopen("123.in","r",stdin); n=read();int Q=read(); for(int i=1;i<n;i++) { int tx=read();int ty=read(); add(tx,ty); add(ty,tx); } num[0]=-1; tot=0; dfs1(1); top[1]=1; dfs2(1); for(;Q;Q--) { if(read()) { write(num[query(read())]); putchar(10); } else { change(1,1,n,dfn[read()]); } } }
p2047
简单的树链剖分.
两遍dfs剖一下.用线段树维护树链上最粗的枝干,每个树链的top再记录自己到父亲的那条边.每次修改就单点修改,查询就边跳边取max.
应该用不着记录"每个树链的top到父亲的那条边",这样看起来很不简洁,应该是我写的太糙了.
p2048
既然没有修改操作,为什么不用树上倍增水过呢?
记录每个点的2^k的祖先和到达那个祖先的路径长度.
查询操作大体上和求lca很相似了.两点路径长就边跳边+=,求x到y的路径上第k个结点有一点点麻烦.先求出lca,这样就可以通过d[]数组得到lca和x之间有几个点.如果在lca和x的路径上就从x往上跳k-1次,否则从y往上跳d[y]+d[x]-2*d[lca]-k+1次.
p2049
继续树链剖分.
dfn[i]表示编号为i的花的dfs序,num[i]表示dfs序为i的花的编号.
用线段树维护链上第一个出现红花的时间戳(dfn),显然只需要贪心一下.
操作一可以单点修改,操作二边取min边往上跳.最后在num里找到编号即可.