BZOJ4012 点分治+排序

点分治:

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


#include 
#include 
#include 
#include 
#include 
 
#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 F[N][5];
bool operator < (data p1,data p2) { return p1.c < p2.c; };
 
struct Monster{ int v; LL L; };
vector 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 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;
}


你可能感兴趣的:(BZOJ4012 点分治+排序)