1. 程式人生 > >洛谷.4115.Qtree4(動態點分治 Heap)

洛谷.4115.Qtree4(動態點分治 Heap)

shu == 感覺 CP include top 長度 pos tails

題目鏈接 洛谷
SPOJ
BZOJ1095(簡化版)

將每次Solve的重心root連起來,會形成一個深度為logn的樹,就叫它點分樹吧。。
我們對每個root維護兩個東西: 它管轄的子樹中所有白點到它上一層(點分樹中的fa[x])的距離(記為h1),以及它的所有子樹中h1的最大值、次大值(這樣就有答案了)(記為h2)
要能隨時插入與刪除距離,同時要取最值,用堆維護即可。刪除用額外一個堆實現。
需要有一個堆Ans統計答案,由每個root的h2去更新Ans。
修改時一個點只會影響其所有祖先節點(有logn個),而且只需要修改值即可(不關心具體路徑),於是直接用堆實現,復雜度O(log^2n)
還需要查詢任意兩點間的距離,dis[a]+dis[b]-2*dis[lca]即可,用RMQ以O(1)查LCA(括號序空間是2倍的).

註意堆修改時一定要先消除它在其它堆裏的貢獻heap.top,修改完再加入heap.top。
另外在訪問每個點x時在h2[x]中加入0,因為2個點才可以對答案有貢獻,x初始為白點是合法的。同時在把它變為黑點時直接可以刪0,避免討論。
最遠邊權是負的答案應是0

能用鏈分治 或 線段樹 括號序列做,快非常多。。以後再說吧
1 2 3 4

//7140ms    83.11MB(O2)
#include <queue>
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=1e5+5,MAXIN=3e5; int n,Min,root,sz[N],Enum,H[N],to[N<<1],nxt[N<<1],val[N<<1],fa[N]; int dis[N],lg[N<<1],tm,cnt,id[N],A[N<<1][18],pos[N];//RMQ for LCA(感覺寫的好麻煩--) bool sta[N],vis[N]; char
IN[MAXIN],*SS=IN,*TT=IN; struct Heap { std::priority_queue<int> h,d; inline void Insert(int x){ h.push(x); } inline void Delete(int x){ d.push(x); } inline int Size(){ return h.size()-d.size(); } inline void Fix(){ while(d.size() && h.top()==d.top()) h.pop(),d.pop(); } inline int Top(){ Fix(); return h.top(); } inline void Pop(){ Fix(), h.pop(); } inline int Sec(){ int t=Top(); h.pop();//註意必要的地方要fix int t2=Top(); h.push(t); return t2; } inline int Two(){ int t=Top(); h.pop();//註意必要的地方要fix int t2=Top(); h.push(t); return t+t2; } void Change(int x,bool s){ if(s) Delete(x); else Insert(x); } }h1[N],h2[N],Ans; inline int read() { int now=0,f=1;register char c=gc(); for(;!isdigit(c);c=gc()) if(c=='-') f=-1; for(;isdigit(c);now=now*10+c-'0',c=gc()); return now*f; } inline void AddEdge(int u,int v,int w) { to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, val[Enum]=w; to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum, val[Enum]=w; } void pre_DFS(int x,int f) { int t=++tm; A[pos[x]=++cnt][0]=t, id[t]=x; for(int i=H[x]; i; i=nxt[i]) if(to[i]!=f) dis[to[i]]=dis[x]+val[i], pre_DFS(to[i],x), A[++cnt][0]=t;//訪問完一棵子樹時再加上 } void Init_RMQ() { for(int i=2; i<=cnt; ++i) lg[i]=lg[i>>1]+1;//lg[]大小2N for(int j=1; j<=lg[cnt]; ++j) for(int i=cnt-(1<<j-1); i; --i)//cnt-(1<<j-1) not n-(1<<j-1)! A[i][j]=std::min(A[i][j-1],A[i+(1<<j-1)][j-1]); } void Get_root(int x,int f,int tot) { int mx=0; sz[x]=1; for(int v,i=H[x]; i; i=nxt[i]) if(!vis[v=to[i]]&&v!=f) { Get_root(v,x,tot), sz[x]+=sz[v]; if(sz[v]>mx) mx=sz[v]; } mx=std::max(mx,tot-sz[x]); if(mx<Min) Min=mx, root=x; } void DFS(int x,int f,int d,Heap &h) {//初始全白 都加進去 h.Insert(d); for(int i=H[x]; i; i=nxt[i]) if(!vis[to[i]]&&to[i]!=f) DFS(to[i],x,d+val[i],h); } inline void Add_Ans(Heap &h){ // if(h.Size()>=2) Ans.Insert(h.Top()+h.Sec()); if(h.Size()>=2) Ans.Insert(h.Two()); } inline void Del_Ans(Heap &h){ // if(h.Size()>=2) Ans.Delete(h.Top()+h.Sec()); if(h.Size()>=2) Ans.Delete(h.Two()); } void Solve(int x) { vis[x]=1, h2[x].Insert(0); for(int v,i=H[x]; i; i=nxt[i]) if(!vis[v=to[i]]) { Heap tmp; DFS(v,x,val[i],tmp); Min=N, Get_root(v,x,sz[v]), fa[root]=x; h1[root]=tmp;//h1[root] h2[x].Insert(tmp.Top()); Solve(root); } Add_Ans(h2[x]); } int LCA(int l,int r) { if(l>r) std::swap(l,r); int k=lg[r-l+1]; return id[std::min(A[l][k],A[r-(1<<k)+1][k])]; } int Calc_dis(int a,int b){ return dis[a]+dis[b]-2*dis[LCA(pos[a],pos[b])]; } void Change(int x,bool s) { Del_Ans(h2[x]), h2[x].Change(0,s), Add_Ans(h2[x]); for(int now=x; fa[now]; now=fa[now]) { Del_Ans(h2[fa[now]]);//! if(h1[now].Size()) h2[fa[now]].Delete(h1[now].Top());//更改前先刪除 h1[now].Change(Calc_dis(x,fa[now]),s);//變得dis是x與fa[now]的,不是now與fa[now]的。。mdzz if(h1[now].Size()) h2[fa[now]].Insert(h1[now].Top()); Add_Ans(h2[fa[now]]); } } inline char get(){ char c=gc(); while(c!='A'&&c!='C') c=gc(); return c; } int main() { n=read(); for(int u,v,w,i=1; i<n; ++i) u=read(),v=read(),w=read(),AddEdge(u,v,w); pre_DFS(1,-1), Init_RMQ(); Min=N, Get_root(1,-1,n), Solve(root); int m=read(),x,white=n;char opt[3]; while(m--) { // scanf("%s",opt); if(/*opt[0]*/get()=='C') x=read(),Change(x,sta[x]^=1),white+=sta[x]?-1:1; else if(!white) puts("They have disappeared."); else printf("%d\n",white>1?std::max(0,Ans.Top()):0); } return 0; }

BZOJ1095

//154024kb  13728ms
//Qtree4弱化版 由於路徑長度均為1,用dep就可以處理RMQ 
#include <queue>
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5,MAXIN=1e6;

int n,Min,root,sz[N],Enum,H[N],to[N<<1],nxt[N<<1],fa[N];
int dep[N],lg[N<<1],cnt,A[N<<1][18],pos[N];
bool sta[N],vis[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Heap
{
    std::priority_queue<int> h,d;
    inline void Insert(int x){
        h.push(x);
    }
    inline void Delete(int x){
        d.push(x);
    }
    inline int Size(){
        return h.size()-d.size();
    }
    inline void Fix(){
        while(d.size() && h.top()==d.top()) h.pop(),d.pop();
    }
    inline int Top(){
        Fix(); return h.top();
    }
    inline int Sec(){
        Fix();
        int t=h.top(); h.pop();
        int t2=h.top(); h.push(t);
        return t2;
    }
    inline int Two(){
        int t=Top(); h.pop();//註意必要的地方要fix 
        int t2=Top(); h.push(t);
        return t+t2;
    }
    void Change(int x,bool s){
        if(s) Delete(x);
        else Insert(x);
    }
}h1[N],h2[N],Ans;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline void AddEdge(int u,int v)
{
    to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
    to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void pre_DFS(int x,int f)
{
    A[pos[x]=++cnt][0]=dep[x];
    for(int i=H[x]; i; i=nxt[i])
        if(to[i]!=f)
            dep[to[i]]=dep[x]+1, pre_DFS(to[i],x), A[++cnt][0]=dep[x];//訪問完一棵子樹時再加上 
}
void Init_RMQ()
{
    for(int i=2; i<=cnt; ++i) lg[i]=lg[i>>1]+1;
    for(int j=1; j<=lg[cnt]; ++j)
        for(int i=cnt-(1<<j-1); i; --i)
            A[i][j]=std::min(A[i][j-1],A[i+(1<<j-1)][j-1]);
}
void Get_root(int x,int f,int tot)
{
    int mx=0; sz[x]=1;
    for(int v,i=H[x]; i; i=nxt[i])
        if(!vis[v=to[i]]&&v!=f)
        {
            Get_root(v,x,tot), sz[x]+=sz[v];
            if(sz[v]>mx) mx=sz[v];
        }
    mx=std::max(mx,tot-sz[x]);
    if(mx<Min) Min=mx, root=x;
}
void DFS(int x,int f,int d,Heap &h)
{//初始全白 都加進去 
    h.Insert(d);
    for(int i=H[x]; i; i=nxt[i])
        if(!vis[to[i]]&&to[i]!=f)
            DFS(to[i],x,d+1,h);
}
inline void Add_Ans(Heap &h){
//  if(h.Size()>=2) Ans.Insert(h.Top()+h.Sec());
    if(h.Size()>=2) Ans.Insert(h.Two());
}
inline void Del_Ans(Heap &h){
//  if(h.Size()>=2) Ans.Delete(h.Top()+h.Sec());
    if(h.Size()>=2) Ans.Delete(h.Two());
}
void Solve(int x)
{
    vis[x]=1, h2[x].Insert(0);
    for(int v,i=H[x]; i; i=nxt[i])
        if(!vis[v=to[i]])
        {
            Heap tmp; DFS(v,x,1,tmp);
            Min=N, Get_root(v,x,sz[v]), fa[root]=x;
            h1[root]=tmp;//h1[root]
            h2[x].Insert(tmp.Top());
            Solve(root);
        }
    Add_Ans(h2[x]);
}
int LCA(int l,int r)
{
    if(l>r) std::swap(l,r);
    int k=lg[r-l+1];
    return std::min(A[l][k],A[r-(1<<k)+1][k]);
}
int Calc_dis(int a,int b){
    return dep[a]+dep[b]-2*LCA(pos[a],pos[b]);
}
void Change(int x,bool s)
{
    Del_Ans(h2[x]), h2[x].Change(0,s), Add_Ans(h2[x]);
    for(int now=x; fa[now]; now=fa[now])
    {
        Del_Ans(h2[fa[now]]);//!
        if(h1[now].Size()) h2[fa[now]].Delete(h1[now].Top());//更改前先刪除 
        h1[now].Change(Calc_dis(x,fa[now]),s);
        if(h1[now].Size()) h2[fa[now]].Insert(h1[now].Top());
        Add_Ans(h2[fa[now]]);
    }
}
inline char get(){
    char c=gc();
    while(c!='G'&&c!='C') c=gc();
    return c;
}

int main()
{
    n=read();
    for(int u,v,i=1; i<n; ++i) u=read(),v=read(),AddEdge(u,v);
    pre_DFS(1,-1), Init_RMQ();
    Min=N, Get_root(1,-1,n), Solve(root);
    int m=read(),x,white=n;
    while(m--)
    {
        if(get()=='C') x=read(),Change(x,sta[x]^=1),white+=sta[x]?-1:1;
        else if(!white) puts("They have disappeared.");
        else printf("%d\n",white>1?Ans.Top():0);
    }
    return 0;
}

洛谷.4115.Qtree4(動態點分治 Heap)