HDU 3966 Aragorn's Story

题意:
给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
思路:
先树链剖分,然后用线段树维护一下

模板题,具体细节看代码

  1 const int maxn = 50000 + 10;
  2 const int maxnode = maxn * 4;
  3 
  4 int n, m, p;
  5 //线段树部分
  6 int add_value, qL, qR;
  7 int addv[maxnode];
  8 void update(int o, int L, int R) 
  9 {
 10     if (qL <= L && R <= qR) 
 11     {
 12         addv[o] += add_value;
 13     }
 14     else 
 15     {
 16         int M = L + (R - L) / 2;
 17         if (qL <= M) update(lson);
 18         if (qR > M) update(rson);
 19     }
 20 }
 21 
 22 void query(int o, int L, int R, LL add) {
 23     if (qL <= L && R <= qR) {
 24         printf("%d
", add + addv[o]);
 25         return;
 26     }
 27     int M = L + (R - L) / 2;
 28     if (qL <= M) query(lson, add + addv[o]);
 29     if (qR > M) query(rson, add + addv[o]);
 30 }
 31 
 32 //树链剖分部分:
 33 //
 34 //u为连接的点,w为边权
 35 struct Edge { int v, w; };
 36 vector<Edge> G[maxn];
 37 
 38 //往往是双向边
 39 void add_edge(int u, int v, int w)
 40 {
 41     G[u].push_back((Edge){v,w});
 42     G[v].push_back((Edge){u,w});
 43 }
 44 
 45 struct Node
 46 {
 47     int size, dep, son, top, fa, ti;
 48     //依次表示第i个节点的:
 49     //子节点数量,深度,所在链的顶端,重儿子,dfs序
 50 } t[maxn];
 51 
 52 int dfs_clock;//DFS时间序列
 53 
 54 void dfs1(int u, int pa, int depth)//第一次DFS,得到size,dep,fa以及son的数据
 55 {
 56     t[u].son = 0; //重儿子,为0表示没有重儿子
 57     t[u].size = 1;    //节点数量
 58     t[u].dep = depth;
 59     t[u].fa = pa;
 60     for (int i = 0; i != G[u].size(); ++ i)
 61     {
 62         int v = G[u][i].v;
 63         if (v == pa) continue;
 64         dfs1(v, u, depth + 1);
 65         t[u].size += t[v].size;
 66         if (t[v].size > t[t[u].son].size) t[u].son = v;
 67     }
 68 }
 69 
 70 void dfs2(int u, int pa)    // 得到时间戳等数据,u为当前节点,pa为父链顶端节点
 71 {
 72     t[u].ti = ++ dfs_clock; //u这个节点的时间戳是dfs_clock,dfs_clock下标是从1开始的,没有0!
 73     t[u].top = pa;        //top是u所在链的顶端
 74     if (t[u].son != 0) dfs2(t[u].son, t[u].top);    //如果节点有重儿子,那么依旧是以pa为链顶端的一条链
 75     for (int i = 0; i != G[u].size(); ++ i)
 76     {
 77         int v = G[u][i].v;
 78         if (v == t[u].son || v == t[u].fa)    continue;//重儿子或者父节点,则跳过
 79         dfs2(v, v);//新的一条链
 80     }
 81 }
 82 
 83 void lca(int x, int y)//更新x到y的之间所有的区间
 84 {
 85     while (t[x].top != t[y].top)
 86     {
 87         if (t[t[x].top].dep < t[t[y].top].dep) swap(x,y); //x深 y浅
 88         qL=t[t[x].top].ti;
 89         qR=t[x].ti;
 90         update(1,1,n);
 91         x = t[t[x].top].fa;
 92     }
 93     if (t[x].dep > t[y].dep) swap(x, y);//x是上面一些的节点
 94     qL=t[x].ti;
 95     qR=t[y].ti;
 96     update(1,1,n);
 97 }
 98 
 99 int value[maxn];
100 void init()
101 {
102     dfs_clock = 0;
103     memset(addv, 0, sizeof(addv));
104     for (int i = 1; i <= n; i++)
105     {
106         scanf("%d", value + i);
107         G[i].clear();
108     }
109     int u, v;
110     for (int i = 1; i <= m; i++)
111     {
112         scanf("%d%d", &u, &v);
113         add_edge(u, v, 0);
114     }
115 }
116 
117 void solve()
118 {
119     dfs1(1, 0, 1);
120     dfs2(1, 0);
121 
122     for (int i = 1; i <= n; i++)
123     {
124         add_value = value[i];
125         qL = qR = t[i].ti;
126         update(1, 1, n);
127     }
128     char op[5];
129     int u, v, w;
130     while (p--)
131     {
132         scanf("%s", op);
133         if (op[0] == 'Q')
134         {
135             scanf("%d", &u);
136             qL = qR = t[u].ti;
137             query(1, 1, n, 0);
138             continue;
139         }
140         scanf("%d%d%d", &u, &v, &w);
141         if (op[0] == 'D') w = -w;
142         add_value = w;
143         lca(u, v);
144     }
145 }
146 
147 int main()
148 {
149     while (scanf("%d%d%d", &n, &m, &p) == 3)
150     {
151         init();
152         solve();
153     }
154     return 0;
155 }
原文地址:https://www.cnblogs.com/liangyongrui/p/6029542.html