【[CF Round #278]Tourists】广义圆方树

最近开始学习圆方树和各种仙人掌(其实基本上感觉门都没怎么入,,怎么明天就要讲了,十分害怕) 主要依靠膜拜immortalCO苟活orz UOJ30

【CF Round #278】Tourists

Cyberland 有 nn 座城市,编号从 11 到 n,有 m 条双向道路连接这些城市。第 jj 条路连接城市 ajaj 和 bj。每天,都有成千上万的游客来到 Cyberland 游玩。 在每一个城市,都有纪念品售卖,第 i 个城市售价为 wi。这个售价有时会变动。 每一个游客的游览路径都有固定起始城市和终止城市,且不会经过重复的城市。 他们会在路径上的城市中,售价最低的那个城市购买纪念品。 你能求出每一个游客在所有合法的路径中能购买的最低售价是多少吗? 你要处理 q 个操作:
  • C a w: 表示 a 城市的纪念品售价变成 w
  • A a b: 表示有一个游客要从 a 城市到 b 城市,你要回答在所有他的旅行路径中最低售价的最低可能值。

输入格式

第一行包含用一个空格隔开的三个数,nmq。 接下来 nn 行,每行包含一个数 wi。 接下来 mm 行,每行包含用一个空格隔开的两个数 aj, bj。(1aj,bjn,ajbj数据保证没有两条道路连接同样一对城市,也没有一条道路两端是相同的城市。并且任意两个城市都可以相互到达。 接下来 qq 行,每行是C a w 或 A a b ,描述了一个操作。

输出格式

对于每一个A类操作,输出一行表示对应的答案。

样例一

input

3 3 3
1
2
3
1 2
2 3
1 3
A 2 3
C 1 5
A 2 3

output

1
2

样例二

input

7 9 4
1
2
3
4
5
6
7
1 2
2 5
1 5
2 3
3 4
2 4
5 6
6 7
5 7
A 2 3
A 6 4
A 6 7
A 3 3

output

2
1
5
3

explanation

一种可能的最优路径是:
  • 2, 3
  • 6, 5, 1, 2, 4
  • 6, 5, 7
  • 3

限制与约定

1n,m,q1051wi109 时间限制:2s 空间限制:256MB 我们发现,圆方树不仅仅可以处理仙人掌问题,他面对处理无向图点双联通分量的时候,也是一把好手。其实广义圆方树相比于普通圆方树,就是一个联通分量一个方点,这意味着在广义圆方树中不会存在圆圆点的存在,圆点相连的一定是方点,方点相连的一定是圆点(对于一个点的联通分量一样要建出方点),且方点连接的所有圆点都属于他的那个环。 那么针对于这道题,我们的方点存储他所管的那一个环的最小值。但是他所管的环不包括这个方点的父亲。因为这方便我们修改圆点的时候不用修改所有和他相连的方点,我们只需要同时修改他父亲的方点就可以了,维护多个值的最小值,multiset或可删除堆都是可以的。由于本题的询问是询问只有路径查询,所以我们如果树剖之后对每一条链都建一颗线段树维护区间最小值,这样的话我们就可以做到严格nlogn(考虑路径完全跨过某个链所花时间是O(1)的而不是O(logn))查询 + nlogn修改。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
const int maxn = 4e5+5;
struct edge{
int la[maxn],nt[maxn],en[maxn],owo;
void adg(int x,int y) { en[++owo]=y; nt[owo]=la[x]; la[x]=owo; }
}V,G;
struct node{
    node *ls,*rs;
    int mi;
}z[maxn],*rt[maxn]; int ccc;
multiset<int>se[maxn];
int n,m,q,tot;
int W[maxn],low[maxn],dfn[maxn],dfx;
int sta[maxn],tp;
void tarjan(int x,int ba) {
    low[x] = dfn[x] = ++dfx;
    sta[++tp] = x;
    for(int it=V.la[x];it;it=V.nt[it]) {
        int y = V.en[it]; if(y==ba) continue;
        if(!dfn[y]) {
            tarjan(y,x);
            low[x] = min(low[x],low[y]);
            if(low[y]>=dfn[x]) {
                ++tot;
                G.adg(x,tot);
                int u;
                do{
                    u = sta[tp--];
                    G.adg(tot,u);
                }while(u!=y);
            } 
        } else low[x] = min(low[x],dfn[y]);
    }
}
int dep[maxn],siz[maxn],fa[maxn],zerz[maxn],spx[maxn],bot[maxn],top[maxn];
void dfs1(int x) {
    siz[x] = 1;
    for(int it=G.la[x];it;it=G.nt[it]) {
        int y = G.en[it]; fa[y] = x; dep[y] = dep[x] + 1;
        dfs1(y); siz[x] += siz[y];
        if(siz[y]>siz[zerz[x]]) zerz[x] = y;
    }
}
void maketree(node *&p,int l,int r) {
    p = &z[++ccc];
    if(l==r) {
        p->mi = *se[sta[l]].begin();
        return;
    }
    int mid = (l+r)>>1;
    maketree(p->ls,l,mid); maketree(p->rs,mid+1,r);
    p->mi = min(p->ls->mi,p->rs->mi);
}
void change(node *&p,int l,int r,int x,int xx) {
    if(l==r) {
        p->mi = *se[xx].begin();
        return;
    }
    int mid = (l+r)>>1;
    if(x<=mid) change(p->ls,l,mid,x,xx);
    else change(p->rs,mid+1,r,x,xx);
    p->mi = min(p->ls->mi,p->rs->mi);
}
int query(node *&p,int l,int r,int x,int y) {
    if(x<=l&&r<=y) return p->mi;
    int mid = (l+r)>>1;
    if(y<=mid) return query(p->ls,l,mid,x,y);
    else if(x>mid) return query(p->rs,mid+1,r,x,y);
    else return min(query(p->ls,l,mid,x,y),query(p->rs,mid+1,r,x,y));
}
void dfs2(int x,int ace) {
    bot[ace] = x; top[x] = ace;
    if(zerz[x]) spx[zerz[x]] = spx[x] + 1,dfs2(zerz[x],ace);

    if(x<=n) se[x].insert(W[x]);
    for(int it=G.la[x];it;it=G.nt[it]) {
        int y = G.en[it];
        if(x>n) se[x].insert(W[y]);
        if(y==zerz[x]) continue;
        spx[y] = 1;
        dfs2(y,y);
    }

    if(ace==x) {
        tp = spx[bot[x]]; int o = bot[x];
        sta[tp] = bot[x];
        if(o!=x) {
            do{
                o = fa[o];
                sta[--tp] = o;
            }while(o!=ace);
        }
        maketree(rt[ace],1,spx[bot[x]]);
    }
}
int query(int x,int y) {
    int ans = 0x3f3f3f3f;
    while(top[x]!=top[y]) {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans = min(ans,query(rt[top[x]],1,spx[bot[top[x]]],1,spx[x]));
        x = fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans = min(ans,query(rt[top[x]],1,spx[bot[top[x]]],spx[x],spx[y]));
    if(x>n) ans = min(ans,W[fa[x]]);
    return ans;
}
int main() {
    scanf("%d%d%d",&n,&m,&q);
    tot = n;
    for(int i=1;i<=n;i++) {
        scanf("%d",&W[i]);
    }
    for(int i=1;i<=m;i++) {
        int x,y; scanf("%d%d",&x,&y);
        V.adg(x,y); V.adg(y,x);
    }
    tarjan(1,0);
    spx[1] = 1; dep[1] = 1;
    dfs1(1); dfs2(1,1);
    char ss[2];
    int x,y;
//  cerr<<"fuck"<<endl;
    for(int i=1;i<=q;i++) {
        scanf("%s%d%d",&ss[0],&x,&y);
        if(ss[0]=='C') {
            if(fa[x]) se[fa[x]].erase(se[fa[x]].find(W[x]));
            se[x].erase(W[x]);
            W[x] = y;
            se[x].insert(W[x]);
            if(fa[x]) se[fa[x]].insert(W[x]);
            change(rt[top[x]],1,spx[bot[top[x]]],spx[x],x);
            if(fa[x]) {
                x = fa[x];
                change(rt[top[x]],1,spx[bot[top[x]]],spx[x],x);
            }
        }
        else printf("%d\n",query(x,y));
    }
}
 
posted @ 2019-01-11 01:14  Newuser233  阅读(5)  评论(0编辑  收藏  举报