把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ3460】Jc的宿舍(树上莫队+树状数组)

点此看题面

大致题意: 一棵树,每个节点有一个人,他打水需要\(T_i\)的时间,每次询问两点之间所有人去打水的最小等待时间。

伪·强制在线

这题看似强制在线,但实际上,\(pre\ mod\ 2\)只能为\(0\)\(1\),因此只要将两种情况下的答案都求出来,最后视情况输出即可。

这样就可以用离线算法乱搞了。

树上莫队+树状数组

其实,这道题是可以用树上莫队来做的。

考虑当前已有若干人要去打水,现在新加入一个人,他的打水时间为\(x\),求改变的贡献值。

显然,根据贪心的思想,我们应让打水时间越久的人越早打水

则设有\(rk\)个人打水时间\(>x\)\(val\)为打水时间\(\le x\)的人打水时间总和,则这个人所需等待时间为\((rk+1)*x+val\)

不难发现,\(rk\)\(val\)两个值是可以用树状数组来进行维护的。

这样这题就做完了。

代码

#include<bits/stdc++.h> 
#define N 50000 
#define LL long long 
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y) 
#define swap(x,y) (x^=y^=x^=y) 
using namespace std; 
int n,query_tot,key,ee,a[N+5],lnk[N+5]; 
struct edge 
{ 
    int to,nxt; 
}e[(N<<1)+5]; 
class Class_FIO 
{ 
    private: 
        #define Fsize 100000 
        #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++) 
        #define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch)) 
        int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize]; 
    public: 
        Class_FIO() {A=B=Fin;} 
        inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));} 
        inline void readc(char &x) {while(isspace(x=tc()));} 
        inline void writeln(LL x) {if(!x) return pc('0'),pc('\n');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);pc('\n');} 
        inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;} 
}F; 
class Class_CaptainMotao_on_Tree//树上莫队
{ 
    private: 
        #define bp(x) (((x)-1)/S+1) 
        #define F5(x) ((v=Di.get_val(a[t=x]),op[t]^=1)?(res+=1LL*(T.QSize(Di.cnt)-T.QSize(v)+1)*a[t]+T.QSum(v),T.Add(v,1,a[t]),0):(T.Add(v,-1,-a[t]),res-=1LL*(T.QSize(Di.cnt)-T.QSize(v)+1)*a[t]+T.QSum(v))) 
        int Q,S,op[N+5];LL ans[N+5][2];char opt[N+5]; 
        class Class_Dfser//DFS预处理
        { 
            private: 
                #define LogN 16 
                int cnt,Depth[N+5],fa[N+5][LogN+5]; 
            public: 
                int s[(N<<1)+5],I[N+5],O[N+5];  
                inline void Init(int x=1,int lst=0) 
                { 
                    register int i; 
                    for(s[I[x]=++cnt]=x,i=1;i<=LogN;++i) fa[x][i]=fa[fa[x][i-1]][i-1]; 
                    for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(Depth[e[i].to]=Depth[fa[e[i].to][0]=x]+1,Init(e[i].to,x),0); 
                    s[O[x]=++cnt]=x; 
                } 
                inline int LCA(int x,int y) 
                { 
                    register int i; 
                    for(Depth[x]<Depth[y]&&swap(x,y),i=0;Depth[x]^Depth[y];++i) ((Depth[x]^Depth[y])&(1<<i))&&(x=fa[x][i]); 
                    if(!(x^y)) return x; 
                    for(i=LogN;~i;--i) fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i]); 
                    return fa[x][0]; 
                } 
        }D; 
        class Class_Discretization//离散化
        { 
            private: 
                int data[N+5]; 
            public: 
                int cnt; 
                inline void Init(int len,int *num)  
                { 
                    for(register int i=1;i<=len;++i) data[i]=num[i]; 
                    sort(data+1,data+len+1),cnt=unique(data+1,data+len+1)-data-1; 
                } 
                inline int get_val(int x) 
                { 
                    register int l=1,r=cnt,mid; 
                    for(mid=l+r>>1;l<=r;mid=l+r>>1) data[mid]<x?l=mid+1:r=mid-1; 
                    return l; 
                } 
        }Di; 
        class Class_TreeArray//树状数组
        { 
            private: 
                #define lowbit(x) (x&-x) 
                int Size[N+5];LL Sum[N+5]; 
            public: 
                int len; 
                inline void Add(int pos,int val1,int val2) {while(pos<=len) Size[pos]+=val1,Sum[pos]+=val2,pos+=lowbit(pos);} 
                inline int QSize(int pos,int res=0) {while(pos) res+=Size[pos],pos-=lowbit(pos);return res;} 
                inline LL QSum(int pos,LL res=0) {while(pos) res+=Sum[pos],pos-=lowbit(pos);return res;} 
        }T; 
        struct Query 
        { 
            int l,r,pos,op,bl,flag; 
            Query(int x=0,int y=0,int p=0,int o=0,int b=0,int f=0):l(x),r(y),pos(p),op(o),bl(b),flag(f){} 
            inline friend bool operator < (Query x,Query y) {return x.bl^y.bl?x.bl<y.bl:(x.bl&1?x.r<y.r:x.r>y.r);} 
        }q[(N<<1)+5]; 
    public: 
        inline void Solve() 
        { 
            int i,x,y,z,k,s=1,t,v,L=1,R=0;LL res=0,lst_ans=0; 
            for(D.Init(),Di.Init(n,a),T.len=Di.cnt,S=sqrt(n),i=1;i<=query_tot;++i)//每个询问分pre%2的值存储两个
            { 
                if(F.readc(opt[i]),F.read(k),opt[i]^'Q') {s=k;continue;} 
                D.I[x=k%n+1]>D.I[y=s]&&swap(x,y),q[++Q]=(z=D.LCA(x,y))^x?Query(D.O[x],D.I[y],i,0,bp(D.O[x]),z):Query(D.I[x],D.I[y],i,0,bp(D.I[x]),0); 
                D.I[x=(k+key)%n+1]>D.I[y=s]&&swap(x,y),q[++Q]=(z=D.LCA(x,y))^x?Query(D.O[x],D.I[y],i,1,bp(D.O[x]),z):Query(D.I[x],D.I[y],i,1,bp(D.I[x]),0); 
            } 
            for(sort(q+1,q+Q+1),i=1;i<=Q;++i)//处理询问
            { 
                while(R<q[i].r) F5(D.s[++R]);while(L>q[i].l) F5(D.s[--L]);while(R>q[i].r) F5(D.s[R--]);while(L<q[i].l) F5(D.s[L++]); 
                q[i].flag&&F5(q[i].flag),ans[q[i].pos][q[i].op]=res,q[i].flag&&F5(q[i].flag); 
            } 
            for(i=1;i<=query_tot;++i) opt[i]^'C'&&(F.writeln(lst_ans=ans[i][lst_ans&1]),0);//输出答案
        } 
}C; 
int main() 
{ 
    register int i,x,y;register char op; 
    for(F.read(n),F.read(query_tot),F.read(key),i=1;i<=n;++i) F.read(a[i]); 
    for(i=1;i<=n;++i) F.read(x),add(x,i); 
    return C.Solve(),F.clear(),0; 
}
posted @ 2018-11-29 19:18  TheLostWeak  阅读(191)  评论(0编辑  收藏  举报