luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]
Posted ZYBGMZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]相关的知识,希望对你有一定的参考价值。
题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
输入输出格式
输入格式:
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来一行n个整数,第i个整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
输出格式:
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
输入输出样例
4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4
4 1 2 2 10 6 5 6 5 16
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
这题本身应该是一题树链剖分果题。。QAQ
1 //不用lazy-tag真是爽! 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 #define inf 0x3f3f3f3f 7 #define ls x<<1 8 #define rs x<<1|1 9 10 int read(){ 11 char ch; 12 int re=0; 13 bool flag=0; 14 while((ch=getchar())!=‘-‘&&(ch<‘0‘||ch>‘9‘)); 15 ch==‘-‘?flag=1:re=ch-‘0‘; 16 while((ch=getchar())>=‘0‘&&ch<=‘9‘) re=re*10+ch-‘0‘; 17 return flag?-re:re; 18 } 19 20 struct Edge{ 21 int to,nxt; 22 Edge(int to=0,int nxt=0): 23 to(to),nxt(nxt){} 24 }; 25 26 struct Segment{ 27 int l,r,su,mx; 28 Segment(){ 29 mx=-inf; 30 } 31 }; 32 33 const int maxn=30005; 34 35 int n,m,cnt=0,dc=1; 36 int head[maxn],val[maxn]; 37 int top[maxn],dep[maxn],fa[maxn],id[maxn],son[maxn],sz[maxn]; 38 Edge G[maxn<<1]; 39 Segment T[maxn<<2]; 40 41 inline void a_ed(int from,int to){ 42 G[++cnt]=Edge(to,head[from]),head[from]=cnt; 43 G[++cnt]=Edge(from,head[to]),head[to]=cnt; 44 } 45 46 inline void push_up(int x){ 47 T[x].mx=max(T[ls].mx,T[rs].mx); 48 T[x].su=T[ls].su+T[rs].su; 49 } 50 51 void build(int x,int l,int r){ 52 T[x].l=l,T[x].r=r; 53 if(l==r){ 54 T[x].su=T[x].mx=val[l]; 55 return; 56 } 57 int mid=l+r>>1; 58 build(ls,l,mid); build(rs,mid+1,r); 59 push_up(x); 60 } 61 62 void update(int x,int M,int c){ 63 if(T[x].l==T[x].r){ 64 T[x].su=T[x].mx=c; 65 return; 66 } 67 int mid=T[x].l+T[x].r>>1; 68 if(M<=mid) update(ls,M,c); 69 else update(rs,M,c); 70 push_up(x); 71 } 72 73 int query(int x,int L,int R,bool kind){ 74 if(L<=T[x].l&&T[x].r<=R) 75 if(kind) return T[x].su; 76 else return T[x].mx; 77 int mid=T[x].l+T[x].r>>1; 78 if(R<=mid) return query(ls,L,R,kind); 79 else if(L>mid) return query(rs,L,R,kind); 80 else{ 81 if(kind) return query(ls,L,mid,kind)+query(rs,mid+1,R,kind); 82 else return max(query(ls,L,mid,kind),query(rs,mid+1,R,kind)); 83 } 84 } 85 86 void dfs1(int no,int p){ 87 fa[no]=p; 88 sz[no]=1; 89 dep[no]=dep[p]+1; 90 for(int e=head[no];e;e=G[e].nxt){ 91 int nt=G[e].to; 92 if(nt!=p){ 93 dfs1(nt,no); 94 sz[no]+=sz[nt]; 95 if(!son[no]||sz[nt]>sz[son[no]]) 96 son[no]=nt; 97 } 98 } 99 } 100 101 void dfs2(int no,int p){ 102 if(!son[no]) return; 103 top[son[no]]=top[no]; 104 id[son[no]]=++dc; 105 dfs2(son[no],no); 106 for(int e=head[no];e;e=G[e].nxt){ 107 int nt=G[e].to; 108 if(nt!=p&&nt!=son[no]){ 109 top[nt]=nt; 110 id[nt]=++dc; 111 dfs2(nt,no); 112 } 113 } 114 } 115 116 int calc(int x,int y,bool kind){ 117 int sum=0,f1=top[x],f2=top[y]; 118 if(!kind) sum=-inf; 119 while(f1!=f2){ 120 if(dep[f1]<dep[f2]){ swap(f1,f2),swap(x,y); } 121 if(kind) 122 sum+=query(1,id[f1],id[x],kind); 123 else 124 sum=max(sum,query(1,id[f1],id[x],kind)); 125 x=fa[f1]; 126 f1=top[x]; 127 } 128 if(dep[x]>dep[y]) swap(x,y); 129 if(kind) sum+=query(1,id[x],id[y],kind); 130 else sum=max(sum,query(1,id[x],id[y],kind)); 131 return sum; 132 } 133 134 int main(){ 135 // freopen("temp.in","r",stdin); 136 n=read(); 137 for(int i=1,from,to;i<n;i++){ 138 from=read(); to=read(); 139 a_ed(from,to); 140 } 141 dfs1(1,0); 142 top[1]=1; 143 id[1]=1; 144 dfs2(1,0); 145 for(int i=1;i<=n;i++) val[id[i]]=read(); 146 build(1,1,n); 147 m=read(); 148 char opt[10]; 149 int x,y; 150 while(m--){ 151 scanf("%s",opt); 152 x=read(),y=read(); 153 switch(opt[1]){ 154 case ‘H‘:{ 155 update(1,id[x],y); 156 break; 157 } 158 case ‘M‘:{ 159 printf("%d\n",calc(x,y,0)); 160 break; 161 } 162 default:{ 163 printf("%d\n",calc(x,y,1)); 164 break; 165 } 166 } 167 } 168 return 0; 169 }
刚学了LCT的我。。想用LCT过了这一题。。
可是。。T了。。QAQ
顺便终于明白、、把一堆变量包进一个结构体里还不用指针构成的splay还不如拆成一个个数组。。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 #define rint register int 6 #define inf 0x3f3f3f3f 7 8 int read(){ 9 char ch; 10 int re=0; 11 bool flag=0; 12 while((ch=getchar())!=‘-‘&&(ch<‘0‘||ch>‘9‘)); 13 ch==‘-‘?flag=1:re=ch-‘0‘; 14 while((ch=getchar())>=‘0‘&&ch<=‘9‘) re=re*10+ch-‘0‘; 15 return flag?-re:re; 16 } 17 18 struct Edge{ 19 int to,nxt; 20 Edge(int to=0,int nxt=0): 21 to(to),nxt(nxt){} 22 }; 23 24 const int maxn=30005; 25 26 int n,m,cnt=0,top; 27 //struct 变 数组 28 int ch[maxn][2],su[maxn],mx[maxn],fa[maxn],rev[maxn]; 29 int head[maxn],val[maxn],stk[maxn]; 30 Edge G[maxn<<1]; 31 32 inline void a_ed(int from,int to){ 33 G[++cnt]=Edge(to,head[from]); 34 head[from]=cnt; 35 G[++cnt]=Edge(from,head[to]); 36 head[to]=cnt; 37 } 38 39 inline void push_up(int x){ 40 mx[x]=max(mx[ch[x][0]],max(mx[ch[x][1]],val[x])); 41 su[x]=su[ch[x][0]]+su[ch[x][1]]+val[x]; 42 } 43 44 inline void push_down(int x){ 45 if(rev[x]){ 46 rev[ch[x][0]]^=1,rev[ch[x][1]]^=1; 47 swap(ch[x][0],ch[x][1]); 48 rev[x]=0; 49 } 50 } 51 52 inline bool isroot(int x){ 53 return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; 54 } 55 56 void rot(int x){ 57 int y=fa[x],z=fa[y],l,r; 58 fa[x]=z; 59 if(!isroot(y)) ch[z][ch[z][1]==y]=x; 60 if(ch[y][0]==x) l=0; 61 else l=1; 62 r=l^1; 63 fa[ch[x][r]]=y; 64 ch[y][l]=ch[x][r]; 65 fa[y]=x; 66 ch[x][r]=y; 67 push_up(y),push_up(x); 68 } 69 70 void splay(int x){ 71 top=1; stk[top]=x; 72 for(rint i=x;!isroot(i);i=fa[i]) stk[++top]=fa[i]; 73 for(rint i=top;i;i--) push_down(stk[i]); 74 while(!isroot(x)){ 75 int y=fa[x],z=fa[y]; 76 if(!isroot(y)){ 77 if((ch[y][0]==x)^(ch[z][0]==y)) rot(x); 78 else rot(y); 79 } 80 rot(x); 81 } 82 } 83 84 void acc(int x){ 85 int t=0; 86 while(x){ 87 splay(x); 88 ch[x][1]=t; 89 push_up(x); 90 t=x; x=fa[x]; 91 } 92 } 93 94 void make_root(int x){ acc(x),splay(x),rev[x]^=1; } 95 96 void split(int x,int y){ make_root(x),acc(y),splay(y); } 97 98 void dfs(int no,int fat){ 99 fa[no]=fat; 100 for(rint e=head[no];e;e=G[e].nxt) 101 if(G[e].to!=fat) 102 dfs(G[e].to,no); 103 } 104 105 int main(){ 106 // freopen("temp.in","r",stdin); 107 n=read(); 108 for(rint i=1,from,to;i<n;i++){ 109 from=read(),to=read(); 110 a_ed(from,to); 111 } 112 memset(mx,-inf,(n+1)<<2); 113 for(rint i=1;i<=n;i++){ 114 val[i]=read(); 115 su[i]=mx[i]=val[i]; 116 } 117 dfs(1,0); 118 char opt[10]; int x,y; 119 m=read(); 120 while(m--){ 121 scanf("%s",opt); 122 x=read(),y=read(); 123 switch(opt[1]){ 124 case ‘H‘:{ 125 acc(x); 126 splay(x); 127 val[x]=y; 128 push_up(x); 129 break; 130 } 131 case ‘M‘:{ 132 split(x,y); 133 printf("%d\n",mx[y]); 134 break; 135 } 136 default:{ 137 split(x,y); 138 printf("%d\n",su[y]); 139 break; 140 } 141 } 142 } 143 return 0; 144 }
以上是关于luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]的主要内容,如果未能解决你的问题,请参考以下文章