uoj #30. 【CF Round #278】Tourists

题意

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

题解

一看题,明显地点双+树链剖分啊
但是有一个问题
我们称每一个新建的,作为点双分量的代替品为S
就是对于每一个S,他的权值是所有和他相邻的点的最小值
我们要考虑维护这一个
但是如果每一次更改吧全部改掉会太麻烦
于是我们考虑一个比较简单的一点的方法
就是S只维护他儿子的最小值
这样就好了啊
因为这颗树是一层是S,一层的原点的,互相交替出现的
所以没有任何问题
有一个小细节就是在查询的时候,如果最后的链段是S,那么你还要查询他的父亲,因为他也是这个点双分量里面的

CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int MAX=1<<30;
const int N=1e6+5;
int n,m,Q;
int w[N];
struct qq
{
    int x,y,last;
}e[N],E[N];int num,Last[N],last[N];
struct H
{
    priority_queue<int> d,s;
    void upd ()
    {
        while (!s.empty()&&!d.empty()&&s.top()==d.top()) s.pop(),d.pop();
    }
    void push (int x)   {s.push(-x);}
    void del (int x) {d.push(-x);}
    int top () {upd();return -s.top();}
}q[N];
void init (int x,int y)
{
    num++;
    //if (num&1) printf("OZY:%d %d\n",x,y);
    e[num].x=x;e[num].y=y;
    e[num].last=last[x];
    last[x]=num;
}
void Init (int x,int y)
{
    num++;
    E[num].x=x;E[num].y=y;
    E[num].last=Last[x];
    Last[x]=num;
}
int dfn[N],low[N],id;
int sta[N],Top;
int cnt;
void dfs (int x)
{
    low[x]=dfn[x]=++id;
    sta[++Top]=x;
    for (int u=Last[x];u!=-1;u=E[u].last)
    {
        int y=E[u].y;
        if (dfn[y]==-1)
        {
            dfs(y);
            low[x]=min(low[x],low[y]);
            if (low[y]>=dfn[x])
            {
                cnt++;int i;
                do
                {
                    i=sta[Top--];
                    init(cnt,i);init(i,cnt);
                }while (i!=y);
                init(cnt,x);init(x,cnt);
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}
int dep[N],tot[N],top[N],son[N],ys[N],f[N];
void dfs1 (int x,int fa)
{
    f[x]=fa;tot[x]=1;dep[x]=dep[fa]+1;
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa) continue;
        if (x>n) q[x].push(w[y]);
        dfs1(y,x);
        tot[x]+=tot[y];
        if (tot[y]>tot[son[x]]) son[x]=y;
    }
}
int ooo=0;
void dfs2 (int x,int tp)
{
    ys[x]=++ooo;top[x]=tp;
    if (son[x]!=0) dfs2(son[x],tp);
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==f[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}
struct qt
{
    int l,r;
    int s1,s2;
    int c;
}tr[N*2];
void bt (int l,int r)
{
    int a=++num;
    tr[a].l=l;tr[a].r=r;
    if (l==r) 
    {
        tr[a].c=0;
        return ;
    }
    int mid=(l+r)>>1;
    tr[a].s1=num+1;bt(l,mid);
    tr[a].s2=num+1;bt(mid+1,r);
}
void change (int now,int x,int y)
{
    if (tr[now].l==tr[now].r)   {tr[now].c=y;return ;}
    int s1=tr[now].s1,s2=tr[now].s2;
    int mid=(tr[now].l+tr[now].r)>>1;
    if (x<=mid) change(s1,x,y);
    else change(s2,x,y);
    tr[now].c=min(tr[s1].c,tr[s2].c);
}
int find (int now,int l,int r)
{
    if (tr[now].l==l&&tr[now].r==r)
        return tr[now].c;
    int s1=tr[now].s1,s2=tr[now].s2;
    int mid=(tr[now].l+tr[now].r)>>1;
    if (r<=mid) return find(s1,l,r);
    else if (l>mid) return find(s2,l,r);
    else return min(find(s1,l,mid),find(s2,mid+1,r));
}
int solve (int x,int y)
{
    int ans=MAX;
    int tx=top[x],ty=top[y];
    if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}
    while (tx!=ty)
    {
        ans=min(ans,find(1,ys[ty],ys[y]));
        y=f[ty];ty=top[y];
        if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}
    }
    if (dep[x]>dep[y]) swap(x,y);
    ans=min(ans,find(1,ys[x],ys[y]));
    if (x>n) ans=min(ans,w[f[x]]);
    return ans;
}
int main()
{
    num=0;memset(last,-1,sizeof(last));
    memset(Last,-1,sizeof(Last));
    scanf("%d%d%d",&n,&m,&Q);cnt=n;
    for (int u=1;u<=n;u++) scanf("%d",&w[u]);
    for (int u=1;u<=m;u++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Init(x,y);Init(y,x);
    }
    memset(dfn,-1,sizeof(dfn));
    dfs(1);
    dfs1(1,0);
    dfs2(1,1);
    for (int u=n+1;u<=cnt;u++) w[u]=q[u].top();
    num=0;bt(1,ooo);
    for (int u=1;u<=cnt;u++)
        change(1,ys[u],w[u]);
    while (Q--)
    {
        char ss[5];
        scanf("%s",ss);
        if (ss[0]=='C')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if (x!=1) 
            {
                q[f[x]].del(w[x]);
                q[f[x]].push(y);
                w[f[x]]=q[f[x]].top();
                change(1,ys[f[x]],w[f[x]]);
            }
            w[x]=y;change(1,ys[x],y);
        }
        else
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",solve(x,y));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值