首页 > 代码库 > HDU 3966 dfs序+LCA+树状数组
HDU 3966 dfs序+LCA+树状数组
题目意思很明白:
给你一棵有n个节点的树,对树有下列操作:
I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k
D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k
Q a 查询节点a的权值
数据大小 节点个数 n[1,50000], 操作次数 op[0,30000];
不会树链剖分 故只有想其他的方法。
这道题有点类似今年上海网络赛的1003 ,不过那题我没做;
算法思路:
以节点1 为根,求出节点i 的 dfs序列 tim[i][2];
其中tim[i][0]存的是进入节点i的时间 ,tim[i][1]存的是离开节点i的时间
看操作: I a b k, 节点a到b的路径上所有点+k;最朴素的算法首先找到他们的最近公共祖先(LCA)(我用RMQ)写的;然后在路径上的每一个节点都+k;
假设树根是1
从a到树根的每一个节点x都满足tim[x][0]<=tim[a][0]<=tim[x][1];如此 如果引入一个数列nt,如果nt(tim[a][0])+=k,那么 nt数列从tim[x][0]到tim[x][1]项的和就加了k,这就相当于把从a到根节点的每一个节点的权值加上了k;
如果节点x不在a到根的路径上呢?那么只有可能是tim[x][0]>tim[a][0] or tim[x][1]<tim[a][0] 故上面的这种做法对其他的点没有影响
根据这种思路 ,那解法就相对简单了:
加上差分数列的思想
a b的LCA是t,把 a b节点都加上k,然后把t的父节点-2;当然 t节点是加了两遍的 所以需要减去一遍 也就是把t节点-1,父节点当然也要+1了
如果有了dfs序,就可以很清晰的看出来 如果一个节点x在这条路径上 那么tim[x][0]<=one of (tim[a][0],tim[b][0])<=tim[x][1];
附上代码渣渣:
1 // hdu 3966 2 #include<iostream> 3 #include<stdio.h> 4 #include<string.h> 5 #include <string> 6 #include <cmath> 7 #include <algorithm> 8 #include <map> 9 #include <set> 10 #include <queue> 11 #include <stack> 12 #include<stdlib.h> 13 #include <vector> 14 using namespace std; 15 16 #define ll __int64 17 #define CL(a,b) memset(a,b,sizeof(a)) 18 #define MAX_NODE 50010 19 20 int n,m,q; 21 22 int log_2(int x) 23 { 24 return (int)(log((double)x)/log(2.0)); 25 } 26 27 int tim[MAX_NODE][2],ti; 28 int rmq[MAX_NODE*2][30],cq,fv[MAX_NODE]; 29 int pre[MAX_NODE]; 30 int value[50010]; 31 32 typedef struct myedge 33 { 34 int v,next; 35 }E; 36 37 E edge[100010]; 38 int head[50010],ce; 39 40 void inithead() 41 { 42 CL(head,-1); 43 ce=0; 44 } 45 void addedge(int s,int e) 46 { 47 edge[ce].v=e;edge[ce].next=head[s];head[s]=ce++; 48 edge[ce].v=s;edge[ce].next=head[e];head[e]=ce++; 49 } 50 51 void initrmq() 52 { 53 int i,j; 54 for(j=1;(1<<j)<=cq;j++) 55 { 56 for(i=1;i+(1<<j)-1<=cq;i++) 57 { 58 rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]); 59 } 60 } 61 } 62 int quermq(int s,int e) 63 { 64 int i=log_2(e-s+1); 65 return min(rmq[s][i],rmq[e-(1<<i)+1][i]); 66 } 67 68 ll nt[50010]; 69 70 int lowbit(int i) 71 { 72 return i&(-i); 73 } 74 75 void modify(int i,ll v) 76 { 77 if(i==0)return ; 78 for(i;i<=n;i+=lowbit(i)) 79 { 80 nt[i]+=v; 81 } 82 } 83 84 ll sum(int i) 85 { 86 ll rem=0; 87 for(i;i>0;i-=lowbit(i)) 88 rem+=nt[i]; 89 return rem; 90 } 91 92 int dfs(int i,int pr) 93 { 94 ti++; 95 tim[i][0]=ti; 96 // cout<<i<<" tim "<<ti<<endl; 97 rmq[++cq][0]=tim[i][0]; 98 fv[i]=cq; 99 pre[ti]=pr;100 int p=head[i];101 while(p!=-1)102 {103 int v=edge[p].v;104 if(tim[v][0]==0)105 {106 dfs(v,tim[i][0]);107 rmq[++cq][0]=tim[i][0];108 }109 p=edge[p].next;110 }111 tim[i][1]=ti;112 return 0;113 }114 115 void inc(int s,int e,int k)116 {117 int rs=fv[s];118 int re=fv[e];119 int rt=quermq(min(rs,re),max(rs,re));120 re=tim[e][0];121 rs=tim[s][0];122 // cout<<rs<<‘ ‘<<re<<‘ ‘<<rt<<‘ ‘<<pre[rt]<<endl;123 if(s==e)124 {125 value[s]+=k;126 return ;127 }128 modify(rs,k);129 modify(re,k);130 modify(rt,-k);131 modify(pre[rt],-k);132 }133 134 void dec(int s,int e,int k)135 {136 k=-k;137 int rs=fv[s];138 int re=fv[e];139 int rt=quermq(min(rs,re),max(rs,re));140 re=tim[e][0];141 rs=tim[s][0];142 if(s==e)143 {144 value[s]+=k;145 return ;146 }147 modify(rs,k);148 modify(re,k);149 modify(rt,-k);150 modify(pre[rt],-k);151 }152 153 ll que(int k)154 {155 int rl=tim[k][0];156 int rr=tim[k][1];157 // cout<<rl<<‘ ‘<<rr<<endl;158 return (ll)value[k]+sum(rr)-sum(rl-1);159 }160 161 char op[3];162 163 164 int main()165 {166 while(scanf("%d %d %d",&n,&m,&q)!=EOF)167 {168 CL(nt,0);169 CL(rmq,0);cq=0;170 CL(fv,0);171 CL(pre,0);172 CL(tim,0);ti=0;173 inithead();174 int i,j,k;175 int a,b,c;176 for(i=1;i<=n;i++)177 {178 scanf("%d",value+i);179 }180 for(i=1;i<n;i++)181 {182 scanf("%d %d",&a,&b);183 addedge(a,b);184 }185 dfs(1,0);186 /*187 for(i=1;i<=cq;i++)188 {189 printf("%d ",rmq[i][0]);190 }cout<<endl;191 */192 initrmq();193 for(i=0;i<q;i++)194 {195 scanf("%s",op);196 if(op[0]==‘I‘)197 {198 scanf("%d %d %d",&a,&b,&c);199 inc(a,b,c);200 }201 else if(op[0]==‘D‘)202 {203 scanf("%d %d %d",&a,&b,&c);204 dec(a,b,c);205 }206 else if(op[0]==‘Q‘)207 {208 scanf("%d",&a);209 printf("%I64d\n",que(a));210 }211 }212 213 }214 215 return 0;216 }
HDU 3966 dfs序+LCA+树状数组