Luogu3241 HNOI2015 开店 动态点分治、前缀和

传送门


如果还没有做过幻想乡战略游戏的话,可以先到这里看看

这道题与幻想乡战略游戏的计算代价那一步的实质其实是一样的。

我们建好点分树,维护这三个东西:

$sumD:$当前点对应的分治范围内年龄在$[L,R]$的妖怪的数量

$sumV:$当前点对应的分治范围年龄在$[L,R]$的妖怪到达分治中心的距离总和

$upV:$当前点对应的分治范围年龄在$[L,R]$的妖怪到达分支中心的父亲的距离总和

然后跟上面那道题一样用类似于容斥和拼凑的方法就可以计算出每一次询问的答案了。

那么问题又来了:怎么维护分治范围内年龄在$[L,R]$的妖怪的数量和距离?

这么考虑:将当前点对应的分治范围内所有点拿出来,按照年龄排序,对距离做前缀和,每一次查询的时候在年龄对应的数组上二分出位置即可。空间复杂度是$O(nlogn)$的

那么我们就在$O(Qlog^2n)$的时间复杂度内完成了这道题

  1 #include<bits/stdc++.h>
  2 #define int long long
  3 #define INF 0x7fffffff
  4 #define P pair < int , int >
  5 //This code is written by Itst
  6 using namespace std;
  7 
  8 inline int read(){
  9     int a = 0;
 10     bool f = 0;
 11     char c = getchar();
 12     while(c != EOF && !isdigit(c)){
 13         if(c == '-')
 14             f = 1;
 15         c = getchar();
 16     }
 17     while(c != EOF && isdigit(c)){
 18         a = (a << 3) + (a << 1) + (c ^ '0');
 19         c = getchar();
 20     }
 21     return f ? -a : a;
 22 }
 23 
 24 const int MAXN = 150010;
 25 struct Edge{
 26     int end , upEd , len;
 27 }Ed[MAXN << 1];
 28 int head[MAXN] , age[MAXN] , fa[MAXN] , size[MAXN] , len[MAXN];
 29 int ST[21][MAXN << 1] , fir[MAXN] , dep[MAXN] , logg2[MAXN << 1];
 30 int N , Q , A , cntEd , ts , nowSize , minSize , minInd;
 31 vector < P > cur[MAXN];
 32 vector < int > up[MAXN];
 33 bool vis[MAXN];
 34 
 35 inline int abss(int a){
 36     return a < 0 ? -a : a;
 37 }
 38 
 39 bool cmpp(P a , P b){
 40     return age[a.first] < age[b.first];
 41 }
 42 
 43 void addEd(int , int , int);
 44 void getSize(int);
 45 void getRoot(int);
 46 void init_dfz(int , int);
 47 void init_dfs(int , int , int);
 48 int cmp(int , int);
 49 void init_st();
 50 void init();
 51 int LCA(int , int);
 52 int calcLen(int , int);
 53 int query(int , int , int);
 54 
 55 signed main(){
 56 #ifndef ONLINE_JUDGE
 57     freopen("3241.in" , "r" , stdin);
 58     //freopen("3241.out" , "w" , stdout);
 59 #endif
 60     N = read();
 61     Q = read();
 62     A = read();
 63     for(int i = 1 ; i <= N ; ++i)
 64         age[i] = read();
 65     for(int i = 1 ; i < N ; ++i){
 66         int a = read() , b = read() , c = read();
 67         addEd(a , b , c);
 68         addEd(b , a , c);
 69     }
 70     init();
 71     int lastans = 0;
 72     for(int i = 1 ; i <= Q ; ++i){
 73         int u = read() , a = read() , b = read();
 74         a = (a + lastans) % A;
 75         b = (b + lastans) % A;
 76         if(a > b)
 77             swap(a , b);
 78         printf("%lld\n" , lastans = query(u , a , b));
 79     }
 80     return 0;
 81 }
 82 
 83 inline void addEd(int a , int b , int c){
 84     Ed[++cntEd].end = b;
 85     Ed[cntEd].upEd = head[a];
 86     Ed[cntEd].len = c;
 87     head[a] = cntEd;
 88 }
 89 
 90 void getSize(int x){
 91     vis[x] = 1;
 92     ++nowSize;
 93     for(int i = head[x] ; i ; i = Ed[i].upEd)
 94         if(!vis[Ed[i].end])
 95             getSize(Ed[i].end);
 96     vis[x] = 0;
 97 }
 98 
 99 void getRoot(int x){
100     vis[x] = size[x] = 1;
101     int maxN = 0;
102     for(int i = head[x] ; i ; i = Ed[i].upEd)
103         if(!vis[Ed[i].end]){
104             getRoot(Ed[i].end);
105             maxN = max(maxN , size[Ed[i].end]);
106             size[x] += size[Ed[i].end];
107         }
108     maxN = max(maxN , nowSize - size[x]);
109     if(maxN < minSize){
110         minSize = maxN;
111         minInd = x;
112     }
113     vis[x] = 0;
114 }
115 
116 
117 void init_dfs(int x , int f , int l){
118     dep[x] = dep[f] + 1;
119     fir[x] = ++ts;
120     len[x] = l;
121     ST[0][ts] = x;
122     for(int i = head[x] ; i ; i = Ed[i].upEd)
123         if(Ed[i].end != f){
124             init_dfs(Ed[i].end , x , l + Ed[i].len);
125             ST[0][++ts] = x;
126         }
127 }
128 
129 inline int cmp(int x , int y){
130     return dep[x] < dep[y] ? x : y;
131 }
132 
133 void init_st(){
134     for(int i = 2 ; i <= N << 1 ; ++i)
135         logg2[i] = logg2[i >> 1] + 1;
136     for(int i = 1 ; 1 << i <= N << 1 ; ++i)
137         for(int j = 1 ; j + (1 << i) <= N << 1 ; ++j)
138             ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
139 }
140 
141 inline int LCA(int x , int y){
142     x = fir[x];
143     y = fir[y];
144     if(y < x)
145         swap(x , y);
146     int t = logg2[y - x + 1];
147     return cmp(ST[t][x] , ST[t][y - (1 << t) + 1]);
148 }
149 
150 inline int calcLen(int x , int y){
151     return len[x] + len[y] - (len[LCA(x , y)] << 1);
152 }
153 
154 void init_dfz(int x , int p){
155     nowSize = 0;
156     minSize = INF;
157     getSize(x);
158     getRoot(x);
159     x = minInd;
160     fa[x] = p;
161     vis[x] = 1;
162     for(int i = x ; i ; i = fa[i])
163         cur[i].push_back(P(x , 0));
164     for(int i = head[x] ; i ; i = Ed[i].upEd)
165         if(!vis[Ed[i].end])
166             init_dfz(Ed[i].end , x);
167     sort(cur[x].begin() , cur[x].end() , cmpp);
168     up[x].push_back(calcLen(cur[x][0].first , fa[x] ? fa[x] : x));
169     cur[x][0].second = calcLen(cur[x][0].first , x);
170     cur[x][0].first = age[cur[x][0].first];
171     for(int i = 1 ; i < cur[x].size() ; ++i){
172         up[x].push_back(up[x][i - 1] + calcLen(cur[x][i].first , fa[x] ? fa[x] : x));
173         cur[x][i].second = cur[x][i - 1].second + calcLen(cur[x][i].first , x);
174         cur[x][i].first = age[cur[x][i].first];
175     }
176     vis[x] = 0;
177 }
178 
179 void init(){
180     init_dfs(1 , 0 , 0);
181     init_st();
182     init_dfz(1 , 0);
183 }
184 
185 
186 inline int query(int x , int l , int r){
187     int sum = 0 , p = x , pastSum = 0 , pastNum = 0 , curSum , curNum;
188     while(x){
189         int t1 = lower_bound(cur[x].begin() , cur[x].end() , P(l , -1)) - cur[x].begin() , t2 = lower_bound(cur[x].begin() , cur[x].end() , P(r + 1 , -1)) - cur[x].begin();
190         curSum = 0;
191         curNum = t2 - t1;
192         if(--t1 >= 0)
193             curSum -= cur[x][t1].second;
194         if(--t2 >= 0)
195             curSum += cur[x][t2].second;
196         sum += curSum - pastSum;
197         sum += calcLen(p , x) * (curNum - pastNum);
198         pastSum = 0;
199         if(t1 >= 0)
200             pastSum -= up[x][t1];
201         if(t2 >= 0)
202             pastSum += up[x][t2];
203         pastNum = curNum;
204         x = fa[x];
205     }
206     return sum;
207 }

猜你喜欢

转载自www.cnblogs.com/Itst/p/10075071.html