BZOJ4012 点分治+排序

来源:互联网 发布:淘宝男鞋 编辑:程序博客网 时间:2024/05/04 10:37

点分治:

记录每个分支根到它管辖所有节点的距离和颜色,按颜色排序后求前缀和。


#include <cassert>#include <iostream>#include <cstdio>#include <vector>#include <algorithm> #define zw for (int i=head[u];i;i=e[i].next)#define y e[i].b#define INF 2147483647#define N 150050 using namespace std; typedef long long LL; struct Edge{ int a,b,v,next; }e[2*N]; struct data{ int c;LL L;}identity;vector<data> F[N][5];bool operator < (data p1,data p2) { return p1.c < p2.c; }; struct Monster{ int v; LL L; };vector<Monster> dis[N];bool operator < (Monster p1,Monster p2) { return p1.v < p2.v; }; int head[N],cnt,n,Q,A;bool vis[N];int c[N],w[N],siz[N],u,a,b,L,R,sum,rt;int bl1[N],bl2[N];LL ans = 0LL; void add(int a,int b,int v) {    e[++cnt].a = a;    e[cnt].b = b;    e[cnt].v = v;    e[cnt].next = head[a];    head[a] = cnt;    return ;} void get_rt(int u,int fa) {    w[u] = 0; siz[u] = 1;    zw if (!vis[y] && y != fa) {        get_rt(y,u);        siz[u] += siz[y];        w[u] = max(siz[y],w[u]);    }    w[u] = max(sum-siz[u],w[u]);    if (w[u] < w[rt]) rt = u;    return ;}  int get_sum(int u,int fa) {    int tmp = 1;    zw         if (!vis[y] && y != fa)            tmp += get_sum(y,u);    return tmp;} void DFS(int u,int fa,int w1,int w2,int len) {    bl1[u] = w1; bl2[u] = w2;    zw if (y != fa && !vis[y]) {        F[w1][w2].push_back( (data){ c[y] , len+e[i].v } );                 dis[w1].push_back( (Monster){ y , len+e[i].v } );                 DFS(y,u,w1,w2,len + e[i].v);    }    return ;}  void solve(int u) {    vis[u] = true; int son = 0;    dis[u].push_back( (Monster) {u,0} );    zw if (!vis[y]) {        ++son;        F[u][son].push_back( (data) {0,0LL} );                 F[u][son].push_back( (data) {c[y],e[i].v} );                 dis[u].push_back( (Monster){y,e[i].v} );                 DFS(y,u,u,son,e[i].v);                 sort( F[u][son].begin() , F[u][son].end() );                 for (int i=1;i<F[u][son].size();i++)            F[u][son][i].L += F[u][son][i-1].L;                 sort( dis[u].begin() , dis[u].end() );    }         zw if (!vis[y]) {        sum = get_sum(y,u);        rt = 0;        get_rt(y,y);        solve(rt);    }} int paul(int u,int i,int c) {    int l = 0 , r = F[u][i].size() - 1;    while (l < r) {        int mid = (l + r + 1) / 2;        int k = F[u][i][mid].c;        if (F[u][i][mid].c <= c) l = mid; else r = mid - 1;    }    return l;} int get_dis(int u,int root) {    assert(dis[u].size() > 0);    int l = 0 , r = dis[u].size() - 1;    while (l < r) {        int mid = (l + r + 1) / 2;        int k = dis[u][mid].v;        if (dis[u][mid].v <= root) l = mid; else r = mid - 1;    }    return dis[u][l].L;} void get_ans(int u,int f,int root) {    LL tmp = 0LL;    LL DIS = get_dis(u,root);    if (L <= c[u] && c[u] <= R) ans += DIS;    for (int i=0;i<4;i++) if (bl2[f] != i && F[u][i].size()) {        int p1 = paul(u,i,L-1) , p2 = paul(u,i,R);        LL k = F[u][i][p2].L - F[u][i][p1].L;        ans += DIS * (p2 - p1) + k;    }    if (bl1[u]) get_ans(bl1[u],u,root);    return ;} int main(){    //freopen("4012.in","r",stdin);    //freopen("4012.out","w",stdout);         //assert(0);    scanf("%d%d%d",&n,&Q,&A);    for (int i=1;i<=n;i++) scanf("%d",&c[i]) , c[i]++;         for (int i=1;i<=n-1;i++) {        int a,b,v;        scanf("%d%d%d",&a,&b,&v);        add(a,b,v); add(b,a,v);    }         sum = n;    w[0] = INF;    rt = 0;    get_rt(1,1);    solve(rt);         bl2[0] = 5;    while (Q--) {        scanf("%d%d%d",&u,&a,&b);        L = (a + ans) % A; L++;        R = (b + ans) % A; R++;        if (L > R) swap(L,R);        ans = 0LL;        get_ans(u,0,u);        #ifdef ONLINE_JUDGE            printf("%lld\n",ans);        #else            printf("%I64d\n",ans);        #endif    }    //fclose(stdin);fclose(stdout);              return 0;}


0 0