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的边

对于原点双中每一条边(u,v),建新边(u,v,1),(v,u,1)

新建点S,T,建边(S,c,2),(a,T,1),(b,T,1)

用拆点的方法,给S,T,c外的每一个点1的容量(拆点过程略)

此时,显然如果S到T的最大流为2,那么存在合法方案

最大流=最小割。显然最小割<=2(割掉(a,T)与(b,T)的边)。割掉新图中任意一条权值为1的边(除(a,T),(b,T)),对应删除原点双的一条边或一个点,显然删除之后原图仍然连通,则新图也连通。因此最小割>1。所以最小割=2

就是说,如果走的时候要穿过一个点双(任意点开始,任意点结束),那么一定可以找到一条合法路径经过点双内权值最小的点

有一个想法:

可以点双缩点成树(圆方树)(每个点双新建一个点,向点双中所有点连边,删除原图中所有边)

(树中代表一个点双的点的权值是点双中点权的最小值)

然后查询就是树上两点路径上最小值,修改就是单点修改(每个点双用一个multiset维护点双中所有点的权值。修改非割点就直接在它属于的点双的multiset中改,如果multiset中最小值变了就对应修改维护最小值的数据结构;修改割点方法在后面),用树剖维护即可

好像还不怎么对。。割点也是属于点双的,但是修改割点权值显然不能暴力修改其属于的所有点双

看了题解,方法是:每个割点就当做属于它在缩点树中的父亲(这个父亲一定代表一个点双;如果不存在父亲就不用维护),每次修改就在这个父亲的multiset那里改;同时每次查询的时候,如果两点的lca代表一个点双,那么除两点路径上最小值外还要考虑lca的父亲(一定是个割点;如果不存在父亲就不用额外查)

然而真的码不动。。5K代码,续了一下午A掉

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<set>
  6 using namespace std;
  7 #define fi first
  8 #define se second
  9 #define mp make_pair
 10 #define pb push_back
 11 typedef long long ll;
 12 typedef unsigned long long ull;
 13 typedef pair<int,int> pii;
 14 struct E
 15 {
 16     int to,nxt;
 17 };
 18 int a[200010];
 19 int n,m,qq;
 20 namespace S
 21 {
 22 #define lc (num<<1)
 23 #define rc (num<<1|1)
 24 int d[800100];
 25 void setx(int L,int x,int l,int r,int num)
 26 {
 27     if(l==r)    {d[num]=x;return;}
 28     int mid=l+((r-l)>>1);
 29     if(L<=mid)    setx(L,x,l,mid,lc);
 30     else    setx(L,x,mid+1,r,rc);
 31     d[num]=min(d[lc],d[rc]);
 32 }
 33 int gmin(int L,int R,int l,int r,int num)
 34 {
 35     if(L<=l&&r<=R)    return d[num];
 36     int mid=l+((r-l)>>1);int ans=0x3f3f3f3f;
 37     if(L<=mid)    ans=min(ans,gmin(L,R,l,mid,lc));
 38     if(mid<R)    ans=min(ans,gmin(L,R,mid+1,r,rc));
 39     return ans;
 40 }
 41 int getmin(int L,int R,int l,int r,int num)
 42 {
 43     if(L>R)    swap(L,R);
 44     //printf("19t%d %d %d\n",L,R,gmin(L,R,l,r,num));
 45     return gmin(L,R,l,r,num);
 46 }
 47 }
 48 int cnt;
 49 int bno[100010];
 50 bool iscut[100010];
 51 namespace T
 52 {
 53 E e[400100];
 54 int f1[200100],ne;
 55 void me(int x,int y)
 56 {
 57     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
 58     e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
 59 }
 60 bool vis[200100];
 61 int sz[200100],hson[200100],tp[200100],dep[200100];
 62 void dfs1(int u,int fa)
 63 {
 64     sz[u]=1;
 65     vis[u]=1;
 66     for(int k=f1[u];k;k=e[k].nxt)
 67         if(e[k].to!=fa)
 68         {
 69             dep[e[k].to]=dep[u]+1;
 70             dfs1(e[k].to,u);
 71             sz[u]+=sz[e[k].to];
 72             if(sz[e[k].to]>sz[hson[u]])
 73                 hson[u]=e[k].to;
 74         }
 75 }
 76 int ar[200100],lp[200100],f[200100];
 77 void dfs2(int u,int fa)
 78 {
 79     ar[++ar[0]]=u;lp[u]=ar[0];
 80     f[u]=fa;
 81     if(u==hson[fa])    tp[u]=tp[fa];
 82     else    tp[u]=u;
 83     if(hson[u])    dfs2(hson[u],u);
 84     for(int k=f1[u];k;k=e[k].nxt)
 85         if(e[k].to!=fa&&e[k].to!=hson[u])
 86             dfs2(e[k].to,u);
 87 }
 88 multiset<int> s[100100];//s[i]维护i号点双里面所有非割点的权值
 89 void update2(int x)
 90 {
 91     a[x+n]=*s[x].begin();
 92     //printf("9t%d %d\n",x,a[x+n]);
 93     S::setx(lp[x+n],a[x+n],1,n+cnt,1);
 94 }
 95 void change(int x,int y)
 96 {
 97     if(!iscut[x])
 98     {
 99         s[bno[x]].erase(s[bno[x]].find(a[x]));
100         s[bno[x]].insert(a[x]=y);
101         update2(bno[x]);
102     }
103     else
104     {
105         if(f[x])
106         {
107             s[f[x]-n].erase(s[f[x]-n].find(a[x]));
108             s[f[x]-n].insert(y);
109             update2(f[x]-n);
110         }
111         a[x]=y;
112         S::setx(lp[x],y,1,n+cnt,1);
113     }
114 }
115 int query(int x,int y)
116 {
117     if(x==y)    return a[x];
118     //printf("99t%d %d\n",x,y);
119     //if(!iscut[x])    x=n+bno[x];
120     //if(!iscut[y])    y=n+bno[y];
121     int ans=0x3f3f3f3f;
122     while(tp[x]!=tp[y])
123     {
124         if(dep[tp[x]]<dep[tp[y]])    swap(x,y);
125         //printf("7t%d %d\n",x,y);
126         ans=min(ans,S::getmin(lp[x],lp[tp[x]],1,n+cnt,1));
127         x=f[tp[x]];
128     }
129     ans=min(ans,S::getmin(lp[x],lp[y],1,n+cnt,1));
130     if(dep[x]>dep[y])    swap(x,y);
131     if(x>n&&f[x])    ans=min(ans,a[f[x]]);
132     return ans;
133 }
134 void work()
135 {
136     int i;
137     /*
138     for(i=1;i<=n+cnt;i++)
139         for(int k=f1[i];k;k=e[k].nxt)
140             printf("1t%d %d\n",i,e[k].to);
141     for(i=1;i<=n;i++)
142         printf("%d ",bno[i]);
143     puts("t2");
144     for(i=1;i<=n;i++)
145         printf("%d ",int(iscut[i]));
146     puts("t3");
147     */
148     for(i=1;i<=n+cnt;i++)
149         if(!vis[i])
150         {
151             dfs1(i,0);
152             dfs2(i,0);
153         }
154     /*
155     for(i=1;i<=ar[0];i++)
156         printf("%d ",ar[i]);
157     puts("t4");
158     for(i=1;i<=n+cnt;i++)
159         printf("%d ",lp[i]);
160     puts("t5");
161     for(i=1;i<=n+cnt;i++)
162         printf("6t%d %d\n",f[i],tp[i]);
163     */
164     for(i=1;i<=n;i++)
165         if(!iscut[i])
166         {
167             s[bno[i]].insert(a[i]);
168             S::setx(lp[i],0x3f3f3f3f,1,n+cnt,1);
169         }
170         else
171         {
172             if(f[i])
173             {
174                 s[f[i]-n].insert(a[i]);
175             }
176             S::setx(lp[i],a[i],1,n+cnt,1);
177         }
178     for(i=1;i<=cnt;i++)
179         update2(i);
180     //for(i=1;i<=ar[0];i++)
181     //    printf("16t%d\n",S::getmin(i,i,1,n+cnt,1));
182 }
183
184 }
185 namespace G
186 {
187 E e[200100];
188 int f1[100010],ne=1;
189 void me(int x,int y)
190 {
191     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
192     e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
193 }
194 int dfc,dfn[100010];
195 pii st[100010];int tp;
196 int dfs(int u,int last)
197 {
198     //printf("3t%d %d\n",u,last);
199     int k,v,lowu=dfn[u]=++dfc,chi=0,lowv;pii x;
200     for(k=f1[u];k;k=e[k].nxt)
201     {
202         v=e[k].to;
203         if(!dfn[v])
204         {
205             st[++tp]=mp(u,v);++chi;
206             lowv=dfs(v,k);lowu=min(lowu,lowv);
207             if(lowv>=dfn[u])
208             {
209                 //printf("4t%d %d\n",u,v);
210                 iscut[u]=1;
211                 ++cnt;
212                 for(;;)
213                 {
214                     x=st[tp--];
215                     if(bno[x.fi]!=cnt)
216                     {
217                         bno[x.fi]=cnt;
218                         T::me(n+cnt,x.fi);
219                     }
220                     if(bno[x.se]!=cnt)
221                     {
222                         bno[x.se]=cnt;
223                         T::me(n+cnt,x.se);
224                     }
225                     if(x.fi==u&&x.se==v)    break;
226                 }
227             }
228         }
229         else if(dfn[v]<dfn[u]&&k!=(last^1))
230         {
231             st[++tp]=mp(u,v);
232             lowu=min(lowu,dfn[v]);
233         }
234     }
235     if(!last&&chi==1)    iscut[u]=0;
236     //printf("5t%d %d %d\n",u,lowu,dfn[u]);
237     return lowu;
238 }
239 }
240
241
242 int main()
243 {
244     char tmp[233];
245     int i,x,y;
246     scanf("%d%d%d",&n,&m,&qq);
247     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
248     for(i=1;i<=m;i++)
249     {
250         scanf("%d%d",&x,&y);
251         G::me(x,y);
252     }
253     for(i=1;i<=n;i++)
254         if(!G::dfn[i])
255             G::dfs(i,0);
256     T::work();
257     while(qq--)
258     {
259         scanf("%s%d%d",tmp,&x,&y);
260         if(tmp[0]==‘C‘)
261         {
262             T::change(x,y);
263         }
264         else
265         {
266             printf("%d\n",T::query(x,y));
267         }
268     }
269     return 0;
270 }

原文地址:https://www.cnblogs.com/hehe54321/p/9803900.html

时间: 2024-10-14 19:42:09

Tourists Codeforces - 487E的相关文章

[Codeforces]487E - Tourists

题目大意:给定无向图,支持修改点权和查询两点间点不重复路径的最小点权.(n,m,q<=10^5) 做法:考虑在一个点双联通分量内,从点双内两点a走到b必有方案经过点双内另一点c,所以类似圆方树,跑tarjan找出每个点双联通分量,删去其中的边,并新建一个点,向该点双内所有点连边,形成一个树的结构,把旧的点称作圆点新的点称为方点,那么两点间最小点权等于树上路径中圆点最小点权和方点相邻点的最小点权的较小值,可以树剖维护,圆点直接维护,方点我们把它在树上的儿子和父亲分开考虑,每个方点开一个堆维护儿子中

【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