bzoj4012:[HNOI2015]开店

传送门

一开始想着二维线段树+二次换根来着,然而空间不够并且强制在线
然后就想到了一个比较好的计算方式,详见bzoj3626[LNOI2014]LCA
就是类似这个统计距离和的方法,不过这次是有边权的,区间修改的话,预处理路径的长度就好了
然后发现还是不好做,看题解去
然后看到了动态点分治(本人过弱,听懂了就是不会写代码,就一直搁着)
还好有拿那个思路写的,先树链剖分用颗主席树维护就好了,才发现可以将年龄那一维用主席树前缀和处理掉
但是空间依然很紧,用一下标记永久化(太久没写标记永久化了,写了好久才写对)
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=2e5+10;
long long ss[maxn],dis[maxn],sum[maxn*30],lastans,s[maxn];
int pre[maxn*2],nxt[maxn*2],h[maxn],v[maxn*2],cnt,tot,f[maxn],ans;
int n,m,A,dep[maxn],size[maxn],w[maxn],top[maxn],id[maxn],tmp;
int rt[maxn],ls[maxn*30],rs[maxn*30],tag[maxn*30];
struct oo{int x,id;}a[maxn];
bool cmp(oo a,oo b){return a.x<b.x;}
void add(int x,int y,int z)
{
    pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,v[cnt]=z;
    pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt,v[cnt]=z;
}
void dfs(int x,int fa)
{
    size[x]=1,f[x]=fa;
    for(rg int i=h[x];i;i=nxt[i])
        if(pre[i]!=fa)dep[pre[i]]=dep[x]+1,dis[pre[i]]=dis[x]+v[i],dfs(pre[i],x),size[x]+=size[pre[i]];
}
void dfs1(int x,int ff)
{
    top[x]=ff,id[x]=++tmp;ss[tmp]=dis[x]-dis[f[x]];int k=0;
    for(rg int i=h[x];i;i=nxt[i])
        if(dep[pre[i]]>dep[x]&&size[pre[i]]>size[k])k=pre[i];
    if(!k)return ;dfs1(k,ff);
    for(rg int i=h[x];i;i=nxt[i])
        if(dep[pre[i]]>dep[x]&&pre[i]!=k)dfs1(pre[i],pre[i]);
}
void change(int x,int &k,int l,int r,int a,int b,int id)
{
    k=++tot,ls[k]=ls[x],rs[k]=rs[x],tag[k]=tag[x],sum[k]=sum[x];
    if(a<=l&&b>=r){tag[k]++;return ;}
    int mid=(l+r)>>1;sum[k]+=ss[min(r,b)]-ss[max(l,a)-1];
    if(a<=mid)change(ls[x],ls[k],l,mid,a,b,id);
    if(b>mid)change(rs[x],rs[k],mid+1,r,a,b,id);
}
void modify(int k,int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        change(rt[k],rt[k],1,n,id[top[x]],id[x],k);
        x=f[top[x]];
    }
    if(id[x]>id[y])swap(x,y);
    change(rt[k],rt[k],1,n,id[x],id[y],k);
}
long long get(int x,int &k,int l,int r,int a,int b,int now)
{
    long long ans=0,mid=(l+r)>>1;
    if(a<=l&&b>=r)return (now+tag[k]-tag[x])*(ss[r]-ss[l-1])+sum[k]-sum[x];
    if(a<=mid)ans+=get(ls[x],ls[k],l,mid,a,b,now+tag[k]-tag[x]);
    if(b>mid)ans+=get(rs[x],rs[k],mid+1,r,a,b,now+tag[k]-tag[x]);
    return ans;
}
long long qsum(int a,int b,int x,int y)
{
    long long ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=get(rt[a],rt[b],1,n,id[top[x]],id[x],0);
        x=f[top[x]];
    }
    if(id[x]>id[y])swap(x,y);
    ans+=get(rt[a],rt[b],1,n,id[x],id[y],0);
    return ans;
}
signed main()
{
    read(n),read(m),read(A);
    for(rg int i=1;i<=n;i++)read(a[i].x),a[i].id=i,w[i]=a[i].x;
    for(rg int i=1,x,y,z;i<n;i++)read(x),read(y),read(z),add(x,y,z);
    dfs(1,0),dfs1(1,1),sort(a+1,a+n+1,cmp),sort(w+1,w+n+1);
    for(rg int i=1;i<=n;i++)ss[i]+=ss[i-1];
    for(rg int i=1;i<=n;i++)
    {
        rt[i]=rt[i-1],s[i]=s[i-1]+dis[a[i].id];
        modify(i,1,a[i].id);
    }
    for(rg int i=1,u,a,b,l,r,x,y;i<=m;i++)
    {
        read(u),read(x),read(y);
        a=min((x+lastans)%A,(y+lastans)%A),b=max((x+lastans)%A,(y+lastans)%A);
        l=lower_bound(w+1,w+n+1,a)-w;
        r=lower_bound(w+1,w+n+1,b+1)-w;r--;
        lastans=dis[u]*(r-l+1)+s[r]-s[l-1]-2*qsum(l-1,r,1,u);
        printf("%lld\n",lastans);
    }
}
posted @ 2019-03-21 19:51  蒟蒻--lichenxi  阅读(...)  评论(... 编辑 收藏