[Codeforces]487E - Tourists

题目大意:给定无向图,支持修改点权和查询两点间点不重复路径的最小点权。(n,m,q<=10^5)

做法:考虑在一个点双联通分量内,从点双内两点a走到b必有方案经过点双内另一点c,所以类似圆方树,跑tarjan找出每个点双联通分量,删去其中的边,并新建一个点,向该点双内所有点连边,形成一个树的结构,把旧的点称作圆点新的点称为方点,那么两点间最小点权等于树上路径中圆点最小点权和方点相邻点的最小点权的较小值,可以树剖维护,圆点直接维护,方点我们把它在树上的儿子和父亲分开考虑,每个方点开一个堆维护儿子中的最小值,修改点权时顺便维护父亲的堆,最后查询时若lca为方点,将其父亲也考虑进答案即可。时间复杂度O(nlog^2n)。

代码:

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<‘0‘||c>‘9‘);
    for(x=c-‘0‘;(c=getchar())>=‘0‘&&c<=‘9‘;)x=x*10+c-‘0‘;
    return x;
}
#define MN 200000
#define N 262144
#define INF 0x3FFFFFFF
struct edge{int nx,t;}e[MN*3+5];
int n,h[MN+5],H[MN+5],en,l[MN+5],d[MN+5],dfn,zx[MN+5],zy[MN+5],zn,u[MN+5];
int w[MN+5],cnt,T[N*2+5],f[MN+5],fa[MN+5],s[MN+5],mx[MN+5];
priority_queue< pair<int,int> > q[MN+5];
inline void ins(int*h,int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
void tj(int x,int fa)
{
    l[x]=d[x]=++dfn;
    for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
        if(d[e[i].t])
        {
            l[x]=min(l[x],d[e[i].t]);
            if(d[e[i].t]<d[x])zx[++zn]=x,zy[zn]=e[i].t;
        }
        else
        {
            zx[++zn]=x;zy[zn]=e[i].t;
            tj(e[i].t,x);l[x]=min(l[x],l[e[i].t]);
            if(l[e[i].t]>=d[x])for(++cnt;zx[zn+1]!=x||zy[zn+1]!=e[i].t;--zn)
            {
                if(u[zx[zn]]!=cnt)u[zx[zn]]=cnt,ins(H,cnt,zx[zn]);
                if(u[zy[zn]]!=cnt)u[zy[zn]]=cnt,ins(H,cnt,zy[zn]);
            }
        }
}
void dfs(int x)
{
    s[x]=1;
    for(int i=H[x];i;i=e[i].nx)if(e[i].t!=fa[x])
    {
        fa[e[i].t]=x;d[e[i].t]=d[x]+1;
        dfs(e[i].t);
        s[x]+=s[e[i].t];
        if(s[e[i].t]>s[mx[x]])mx[x]=e[i].t;
    }
}
void build(int x)
{
    l[x]=++dfn;
    if(!f[x])f[x]=x;
    if(mx[x])f[mx[x]]=f[x],build(mx[x]);
    for(int i=H[x];i;i=e[i].nx)
        if(e[i].t!=fa[x]&&e[i].t!=mx[x])build(e[i].t);
}
int query(int l,int r)
{
    int res=INF;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)res=min(res,T[l+1]);
        if( r&1)res=min(res,T[r-1]);
    }
    return res;
}
void renew(int k,int x){for(T[k+=N]=x;k>>=1;)T[k]=min(T[k<<1],T[k<<1|1]);}
void change(int k,int x)
{
    renew(l[k],w[k]=x);if(!fa[k])return;
    q[fa[k]].push(make_pair(-x,k));
    while(-q[fa[k]].top().first<w[q[fa[k]].top().second])q[fa[k]].pop();
    renew(l[fa[k]],-q[fa[k]].top().first);
}
int Q(int x,int y)
{
    int res=INF;
    for(;f[x]!=f[y];x=fa[f[x]])
    {
        if(d[f[x]]<d[f[y]])swap(x,y);
        res=min(res,query(l[f[x]],l[x]));
    }
    if(l[x]>l[y])swap(x,y);
    if(x>n)res=min(res,T[l[fa[x]]+N]);
    return min(res,query(l[x],l[y]));
}
int main()
{
    int m,q,i;char s[5];
    cnt=n=read();m=read();q=read();
    for(i=1;i<=n;++i)w[i]=read();
    while(m--)ins(h,read(),read());
    tj(1,0);dfs(1);d[1]=dfn=0;build(1);
    for(i=1;i<2*N;++i)T[i]=INF;
    for(i=1;i<=n;++i)change(i,w[i]);
    while(q--)
    {
        scanf("%s",s);
        if(s[0]==‘C‘)i=read(),change(i,read());
        else printf("%d\n",Q(read(),read()));
    }
}
时间: 2024-10-14 19:10:54

[Codeforces]487E - Tourists的相关文章

Tourists Codeforces - 487E

https://codeforces.com/contest/487/problem/E http://uoj.ac/problem/30 显然割点走过去就走不回来了...可以看出题目跟点双有关 有一个结论:如果在点双中有不同的点a,b,c,那么一定存在点不重复的路径从a到c再到b. 证明(摘自https://codeforces.com/blog/entry/14832): 显然这样的点双中,点数>=3,因此移除任意点或任意边,仍然连通 新建一张网络流图.用边(u,v,w)表示从u到v容量为w

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st

Codeforces 772A Voltage Keepsake - 二分答案

You have n devices that you want to use simultaneously. The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λ·ai units of power. The i-th device currently has bi units of power store

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Codeforces Round #408 (Div. 2) B

Description Zane the wizard is going to perform a magic show shuffling the cups. There are n cups, numbered from 1 to n, placed along the x-axis on a table that has m holes on it. More precisely, cup i is on the table at the position x?=?i. The probl

Codeforces 617 E. XOR and Favorite Number

题目链接:http://codeforces.com/problemset/problem/617/E 一看这种区间查询的题目,考虑一下莫队. 如何${O(1)}$的修改和查询呢? 令${f(i,j)}$表示区间${\left [ l,r \right ]}$内数字的异或和. 那么:${f(l,r)=f(1,r)~~xor~~f(1,l-1)=k}$ 记一下前缀异或和即可维护. 1 #include<iostream> 2 #include<cstdio> 3 #include&l