1. 程式人生 > >[圓方樹][樹鏈剖分][set]JZOJ 5909 跑商

[圓方樹][樹鏈剖分][set]JZOJ 5909 跑商

Description

題目背景:
尊者神高達很窮,所以他需要跑商來賺錢
題目描述:
基三的地圖可以看做 n 個城市,m 條邊的無向圖,尊者神高達會從任意一個點出發並在起點購買貨物,在旅途中任意一點賣出並最終到達終點,尊者神高達的時間很寶貴,所以他不會重複經過同一個城市,但是為了掙錢,他可能會去繞路。當然,由於工作室氾濫,所以一個城市的貨物價格可能會發生改變。但是尊者神高達智商不足,他可能在一個很蠢的節點把貨物賣掉,所以尊者神高達想知道每一次跑商最多能賠多少錢。
 

Input

第一行 n,m;
接下來 1 行 n 個數,代表每個城市貨物的價格;
接下來 m 行 u,v 代表一條邊
接下來 1 行 Q
接下來 Q 行
C x w 代表城市 x 的貨物價格變為 w
Q u v 代表一次從 u 到 v 的跑商

Output

如題目描述
 

Sample Input

3 3 
1 2 3
1 2
2 3
1 3
3
Q 2 3
C 1 5
Q 1 3
 

Sample Output

1
3

樣例解釋:
1,2,3 都聯通,起點購買價格為 2,在 1 點賣出賠得最多2-1=1
更新後每個點價值為 5,2,3
起點價格為 5,在 2 點賣出賠得最多,5-2=3
 

Data Constraint

40%的資料為一棵樹
另外 20%的資料沒有修改操作
所以資料滿足 n,m,q<=100000;保證圖聯通,資料合法
 

Hint

Tips:資料很水可以嘗試瞎搞演算法,1,2 兩道題演算法我暑假講過類似的,各位隨便 AC,第三題應該有不少大佬見過原題 orz。

分析

原題怪!

這題我們轉換成圓方樹,然後對於方點,我們儲存的值為所連葉子節點的最小值(雖然父親也是環的一部分但是算進去很麻煩)用set維護

然後樹鏈剖分即可

對於LCA為方點的特殊情況,我們要特判一下它的父親

 

#include <iostream>
#include <cstdio>
#include <set>
#include <stack>
using namespace std;
const int N=1e6+10;
struct Node {
    int sz,son,top,fa,seg,dep,w;
}t[N];
int rev[N],scnt;
struct Edge {
    int u,v,nx;
}g[4*N],e[2*N];
int cnt,elist[N],list[2*N];
int s[4*N];
int low[N],dfn[N],tme;
stack<int> stk;
multiset<int> sqr[N];
int sqcnt;
int n,m,q;

void Adde(int u,int v) {
    e[++cnt].u=u;e[cnt].v=v;e[cnt].nx=elist[u];elist[u]=cnt;
}

void Add(int u,int v) {
    g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt;
}

void Tarjan(int u,int fa) {
    low[u]=dfn[u]=++tme;stk.push(u);
    for (int i=elist[u];i;i=e[i].nx)
        if (e[i].v!=fa)
            if (!dfn[e[i].v]) {
                Tarjan(e[i].v,u);
                if (low[e[i].v]>=dfn[u]) {
                    Add(++sqcnt,u);Add(u,sqcnt);
                    while (!stk.empty()&&stk.top()!=e[i].v) Add(sqcnt,stk.top()),Add(stk.top(),sqcnt),stk.pop();
                    Add(sqcnt,e[i].v),Add(e[i].v,sqcnt),stk.pop();
                }
                else low[u]=min(low[u],low[e[i].v]);
            }
            else low[u]=min(low[u],dfn[e[i].v]);
}

void Dfs1(int u,int fa) {
    t[u].fa=fa;t[u].sz=1;t[u].dep=t[fa].dep+1;
    if (fa>n) sqr[fa-n].insert(t[u].w);
    for (int i=list[u];i;i=g[i].nx)
        if (g[i].v!=fa) {
            Dfs1(g[i].v,u);
            t[u].sz+=t[g[i].v].sz;
            if (t[g[i].v].sz>t[t[u].son].sz) t[u].son=g[i].v;
        }
}

void Dfs2(int u,int fa) {
    int son=t[u].son;
    if (u>n) t[u].w=*sqr[u-n].begin();
    if (son) {
        t[son].seg=++scnt;
        rev[scnt]=son;
        t[son].top=t[u].top;
        Dfs2(son,u);
    }
    for (int i=list[u];i;i=g[i].nx)
        if (!t[g[i].v].top) {
            t[g[i].v].seg=++scnt;
            rev[scnt]=g[i].v;
            t[g[i].v].top=g[i].v;
            Dfs2(g[i].v,u);
        }
}

void Build(int l,int r,int x) {
    if (l==r) {
        s[x]=t[rev[l]].w;
        return;
    }
    int mid=l+r>>1;
    Build(l,mid,x<<1);Build(mid+1,r,(x<<1)+1);
    s[x]=min(s[x<<1],s[(x<<1)+1]);
}

void Change(int l,int r,int w,int k,int x) {
    if (l>k||k>r) return;
    if (l==r&&r==k) {
        s[x]=w;
        return;
    }
    int mid=l+r>>1;    
    if (mid>=k) Change(l,mid,w,k,x<<1);
    if (mid<k) Change(mid+1,r,w,k,(x<<1)+1);
    s[x]=min(s[x<<1],s[(x<<1)+1]);
}

int Query_Seg(int l,int r,int ll,int rr,int x) {
    if (l>rr||ll>r) return 2147483647;
    if (ll<=l&&r<=rr) return s[x];
    int mid=l+r>>1,ans=2147483647;
    if (ll<=mid) ans=Query_Seg(l,mid,ll,rr,x<<1);
    if (mid<rr) ans=min(ans,Query_Seg(mid+1,r,ll,rr,(x<<1)+1));
    return ans;
}

int Query_Tree(int x,int y) {
    int fx=t[x].top,fy=t[y].top;
    int ans=2147483647;
    while (fx!=fy) {
        if (t[fx].dep<t[fy].dep) swap(x,y),swap(fx,fy);
        ans=min(ans,Query_Seg(1,scnt,t[fx].seg,t[x].seg,1));
        x=t[fx].fa;fx=t[x].top;
    }
    if (t[x].dep>t[y].dep) swap(x,y);
    return min(min(ans,x>n?t[t[x].fa].w:2147483647),Query_Seg(1,scnt,t[x].seg,t[y].seg,1));
}

int main() {
    freopen("paoshang.in","r",stdin);
    freopen("paoshang.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&t[i].w);
    for (int i=1;i<=m;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        Adde(u,v);Adde(v,u);
    }
    sqcnt=n;cnt=0;Tarjan(1,0);
    Dfs1(1,0);
    scnt=rev[1]=t[1].top=t[1].seg=1;
    Dfs2(1,0);
    Build(1,scnt,1);
    scanf("%d",&q);
    for (int i=1;i<=q;i++) {
        char c;
        do {
            scanf("%c",&c);
        }
        while (c!='Q'&&c!='C');
        int u,v;
        scanf("%d%d",&u,&v);
        if (c=='Q') printf("%d\n",t[u].w-Query_Tree(u,v));
        else {
            Change(1,scnt,v,t[u].seg,1);
            if (t[u].fa>n) {
                sqr[t[u].fa-n].erase(sqr[t[u].fa-n].find(t[u].w));
                sqr[t[u].fa-n].insert(v);
                int fake=*sqr[t[u].fa-n].begin();
                if (t[t[u].fa].w!=fake) t[t[u].fa].w=fake,Change(1,scnt,fake,t[t[u].fa].seg,1);
            }
            t[u].w=v;
        }
    }
}
View Code