1. 程式人生 > >洛谷 P3313 [SDOI2014]旅行 解題報告

洛谷 P3313 [SDOI2014]旅行 解題報告

HA 發生 間隔 如果 節省空間 query tro oid 問題

P3313 [SDOI2014]旅行

題目描述

S國有N個城市,編號從1到N。城市間用N-1條雙向道路連接,滿足從一個城市出發可以到達其它所有城市。每個城市信仰不同的宗教,如飛天面條神教、隱形獨角獸教、絕地教都是常見的信仰。

為了方便,我們用不同的正整數代表各種宗教, S國的居民常常旅行。旅行時他們總會走最短路,並且為了避免麻煩,只在信仰和他們相同的城市留宿。當然旅程的終點也是信仰與他相同的城市。S國政府為每個城市標定了不同的旅行評級,旅行者們常會記下途中(包括起點和終點)留宿過的城市的評級總和或最大值。

在S國的歷史上常會發生以下幾種事件:

“CC x c“:城市x的居民全體改信了c教;

“CW x w“:城市x的評級調整為w;

“QS x y“:一位旅行者從城市x出發,到城市y,並記下了途中留宿過的城市的評級總和;

“QM x y“:一位旅行者從城市x出發,到城市y,並記下了途中留宿過的城市的評級最大值。

由於年代久遠,旅行者記下的數字已經遺失了,但記錄開始之前每座城市的信仰與評級,還有事件記錄本身是完好的。請根據這些信息,還原旅行者記下的數字。 為了方便,我們認為事件之間的間隔足夠長,以致在任意一次旅行中,所有城市的評級和信仰保持不變。

輸入輸出格式

輸入格式:

輸入的第一行包含整數N,Q依次表示城市數和事件數。

接下來N行,第i+l行兩個整數Wi,Ci依次表示記錄開始之前,城市i的評級和信仰。 接下來N-1行每行兩個整數x,y表示一條雙向道路。

接下來Q行,每行一個操作,格式如上所述。

輸出格式:

對每個QS和QM事件,輸出一行,表示旅行者記下的數字。

說明

N,Q < =10^5 , C < =10^5

數據保證對所有QS和QM事件,起點和終點城市的信仰相同;在任意時

刻,城市的評級總是不大於10^4的正整數,且宗教值不大於C。


首先把題目細節讀到位,第一行有“用N-1條雙向道路連接”,這是一顆樹。樹中每個點都有一些不同的屬性,當走過一條鏈時,只詢問鏈上一種屬性的點。

對於樹鏈操作,我們考慮用樹剖維護;對於每種屬性的點,我們分別建立一顆線段樹來維護。

值得一提的是,建很多個線段樹的方法大多數被稱為主席樹,其實這麽理解沒什麽問題,但如果可以的話,我更想用動態開點線段樹

來稱呼它(通過 只建立需要訪問的點的所在鏈 以達到節省空間的目的)

而主席樹基礎做法:靜態區間維護第K大值,則是基於節點共用以節省空間的。


#include <cstdio>
#define ls t[id].ch[0]
#define rs t[id].ch[1]
#define mid (l+r>>1)
#define Mid (L+R>>1)
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
const int N=100010;
int head[N],cnt=0,next[N<<1],to[N<<1];
int f[N],siz[N],dfn[N],ws[N],top[N],dep[N],time=0;
void add(int u,int v){next[++cnt]=head[u];to[cnt]=v;head[u]=cnt;}
void dfs1(int now)
{
    for(int i=head[now];i;i=next[i])
    {
        int v=to[i];
        if(f[now]!=v)
        {
            f[v]=now;
            dep[v]=dep[now]+1;
            dfs1(v);
            siz[now]+=siz[v];
            if(siz[ws[now]]<siz[v])
                ws[now]=v;
        }
    }
    siz[now]++;
}
void dfs2(int now,int anc)
{
    dfn[now]=++time;
    top[now]=anc;
    if(!ws[now]) return;
    dfs2(ws[now],anc);
    for(int i=head[now];i;i=next[i])
    {
        int v=to[i];
        if(!dfn[v])
            dfs2(v,v);
    }
}
struct node
{
    int ch[2],mx,sum;
}t[N*25];
int tot=0,typ[N],c[N],root[N],n,q;
int New(int dat)
{
    t[++tot].mx=dat,t[tot].sum=dat;
    return tot;
}
int change(int id,int l,int r,int loc,int dat)
{
    if(!id) id=New(dat);
    if(l==r) {t[id].mx=dat;t[id].sum=dat;return id;}
    if(loc<=mid) ls=change(ls,l,mid,loc,dat);
    else rs=change(rs,mid+1,r,loc,dat);
    t[id].mx=max(t[ls].mx,t[rs].mx);
    t[id].sum=t[ls].sum+t[rs].sum;
    return id;
}
int query_s(int id,int L,int R,int l,int r)
{
    if(!id)  return 0;
    if(L==l&&R==r) return t[id].sum;
    if(r<=Mid) return query_s(ls,L,Mid,l,r);
    else if(l>Mid) return query_s(rs,Mid+1,R,l,r);
    else return query_s(ls,L,Mid,l,Mid)+query_s(rs,Mid+1,R,Mid+1,r);
}
int query_m(int id,int L,int R,int l,int r)
{
    if(!id)  return 0;
    if(L==l&&R==r) return t[id].mx;
    if(r<=Mid) return query_m(ls,L,Mid,l,r);
    else if(l>Mid) return query_m(rs,Mid+1,R,l,r);
    else return max(query_m(ls,L,Mid,l,Mid),query_m(rs,Mid+1,R,Mid+1,r));
}
void t_Q_sum(int x,int y)
{
    int ty=typ[x],ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]])
        {
            ans+=query_s(root[ty],1,n,dfn[top[x]],dfn[x]);
            x=f[top[x]];
        }
        else
        {
            ans+=query_s(root[ty],1,n,dfn[top[y]],dfn[y]);
            y=f[top[y]];
        }
    }
    ans+=query_s(root[ty],1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]));
    printf("%d\n",ans);
}
void t_Q_mx(int x,int y)
{
    int ty=typ[x],ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]])
        {
            ans=max(ans,query_m(root[ty],1,n,dfn[top[x]],dfn[x]));
            x=f[top[x]];
        }
        else
        {
            ans=max(ans,query_m(root[ty],1,n,dfn[top[y]],dfn[y]));
            y=f[top[y]];
        }
    }
    ans=max(ans,query_m(root[ty],1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y])));
    printf("%d\n",ans);
}
int main()
{
    scanf("%d%d",&n,&q);
    int u,v;
    for(int i=1;i<=n;i++) scanf("%d%d",c+i,typ+i);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs1(1);
    dfs2(1,1);
    for(int i=1;i<=n;i++)
        root[typ[i]]=change(root[typ[i]],1,n,dfn[i],c[i]);
    for(int i=1;i<=q;i++)
    {
        int x,y;char opt[18];
        scanf("%s%d%d",opt,&x,&y);
        if(opt[1]==‘C‘)
        {
            root[typ[x]]=change(root[typ[x]],1,n,dfn[x],0);
            typ[x]=y;
            root[typ[x]]=change(root[typ[x]],1,n,dfn[x],c[x]);
        }
        else if(opt[1]==‘W‘)
        {
            root[typ[x]]=change(root[typ[x]],1,n,dfn[x],y);
            c[x]=y;
        }    
        else if(opt[1]==‘S‘)
            t_Q_sum(x,y);
        else
            t_Q_mx(x,y);
    }
    return 0;
}

2018.6.17

洛谷 P3313 [SDOI2014]旅行 解題報告