FJ省队集训DAY3 T2

思路:如果一个DAG要的路径上只要一条边去切掉,那么要怎么求?很容易就想到最小割,但是如果直接做最小割会走出重复的部分,那我们就这样:反向边设为inf,这样最小割的时候就不会割到了,判断无解我们直接用tarjan

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #define ll long long
  7 const ll inf = 1ll << 60;
  8 struct edge{
  9     int u,v,w;
 10 }e[200005];
 11 ll flow[200005];
 12 int op[200005],dis[200005],cnt[200005],a[115][115],pd[10005];
 13 int tot,go[200005],next[200005],first[200005],S,T,nodes,sz;
 14 int n,m,vis[200005],instack[200005],c[200005],top,dfn[200005],low[200005],belong[200005],num;
 15 int read(){
 16     int t=0,f=1;char ch=getchar();
 17     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘)f=-1;ch=getchar();}
 18     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
 19     return t*f;
 20 }
 21 void insert(int x,int y){
 22     tot++;
 23     go[tot]=y;
 24     next[tot]=first[x];
 25     first[x]=tot;
 26 }
 27 void insert(int x,int y,ll z){
 28     tot++;
 29     go[tot]=y;
 30     next[tot]=first[x];
 31     first[x]=tot;
 32     flow[tot]=z;
 33 }
 34 void add(int x,int y,ll z){
 35     insert(x,y,z);op[tot]=tot-1;
 36     insert(y,x,inf);op[tot]=tot+1;
 37 }
 38 void tarjan(int x){
 39     vis[x]=instack[x]=1;
 40     c[++top]=x;dfn[x]=low[x]=++sz;
 41     for (int i=first[x];i;i=next[i]){
 42         int pur=go[i];
 43         if (!vis[pur]){
 44             tarjan(pur);
 45             low[x]=std::min(low[x],low[pur]);
 46         }else if (instack[pur]){
 47             low[x]=std::min(low[x],dfn[pur]);
 48         }
 49     }
 50     if (low[x]==dfn[x]){
 51         num++;
 52         while (c[top]!=x){
 53             belong[c[top]]=num;
 54             instack[c[top]]=0;
 55             top--;
 56         }
 57             belong[c[top]]=num;
 58             instack[c[top]]=0;
 59             top--;
 60     }
 61 }
 62 ll dfs(int x,ll f){
 63     if (x==T) return f;
 64     int mn=nodes;ll sum=0;
 65     for (int i=first[x];i;i=next[i]){
 66         int pur=go[i];
 67         if (flow[i]&&dis[pur]+1==dis[x]){
 68             ll F=std::min(f-sum,flow[i]);
 69             ll save=dfs(pur,F);
 70             flow[i]-=save;
 71             flow[op[i]]+=save;
 72             sum+=save;
 73             if (dis[S]>=nodes||f==sum) return sum;
 74         }
 75         if (flow[i]) mn=std::min(mn,dis[pur]);
 76     }
 77     if (sum==0){
 78         cnt[dis[x]]--;
 79         if (cnt[dis[x]]==0){
 80             dis[S]=nodes;
 81         }else{
 82             dis[x]=mn+1;
 83             cnt[dis[x]]++;
 84         }
 85     }
 86     return sum;
 87 }
 88 int main(){
 89     n=read();m=read();
 90     for (int i=1;i<=m;i++){
 91         e[i].u=read()+1,e[i].v=read()+1,e[i].w=read();
 92         a[e[i].u][e[i].v]=1;
 93         insert(e[i].u,e[i].v);
 94     }
 95     for (int i=1;i<=n;i++)
 96      if (!vis[i]) tarjan(i);
 97     if (belong[1]==belong[n]){
 98         puts("-1");
 99         return 0;
100     }
101     for (int i=1;i<=n;i++)
102      a[i][i]=1;
103     for (int k=1;k<=n;k++)
104      for (int i=1;i<=n;i++)
105       for (int j=1;j<=n;j++)
106        a[i][j]|=a[i][k]&&a[k][j];
107     for (int i=1;i<=n;i++)
108      if (a[1][i]&&a[i][n]) pd[i]=1;
109     for (int i=1;i<=m;i++)
110      if (pd[e[i].u]&&pd[e[i].v])
111       add(e[i].u,e[i].v,e[i].w);
112     S=1;T=n;nodes=n;
113     int ans=0;
114     while (dis[S]<nodes&&ans<inf) ans+=dfs(S,inf);
115     if (ans==0) printf("-1");
116     else printf("%d\n",ans);
117 }
时间: 2024-12-30 03:25:33

FJ省队集训DAY3 T2的相关文章

FJ省队集训DAY3 T1

思路:我们考虑如果取掉一个部分,那么能影响到最优解的只有离它最近的那两个部分. 因此我们考虑堆维护最小的部分,离散化离散掉区间,然后用线段树维护区间有没有雪,最后用平衡树在线段的左右端点上面维护最小的id 我讲的貌似不是很清楚.. 还有,蜜汁80分,打死也改不出来.. 1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algo

FJ省队集训DAY2 T2

思路:我们可以考虑三角剖分,这样问题就变成考虑三角形的选取概率和三角形内有多少个点了. 先用树状数组预处理出三角剖分的三角形中有多少个点,然后用线段树维护,先用原点极角排序,然后枚举i,再以i极角排序,此时线段树的作用就来了,每次到一个询问的教室点,我们就在线段树里面查找之前的概率,统计贡献即可. 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #

FJ省队集训DAY4 T2

XXX 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 using namespace std; 8 typedef unsigned long long ll; 9 ll a,mod=1,L=1; 10 ll tr[4],b[4],tmp[4

FJ省队集训最终测试 T2

思路:发现如果一个人一共选了x个点,那么选中某一个点对的概率都是一样的,一个人选x个点的总方案是C(n,x),一个人选中某个点对的总方案是C(n-2,x-2),这样,那么选中某个点对的概率就是 x*(x-1)/(n*(n-1)),这样,我们就用树分治求出有多少对符合条件的对数,然后乘上每个人的概率即可. 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring>

FJ省队集训DAY1 T1

题意:有一堆兔子,还有一个r为半径的圆,要求找到最大集合满足这个集合里的兔子两两连边的直线不经过圆. 思路:发现如果有两个点之间连边不经过圆,那么他们到圆的切线会构成一段区间,那么这两个点的区间一定会有交集,形如s0 s1 e0 e1 同样的,如果是n个点,那就是s0 s1 s2..sn e0 e1 e2.. en 因此,我们枚举那个起始点,然后对于其他点我们按照s排序,对于e做最长上升子序列即可.时间复杂度O(n^2 logn) 1 #include <cstdio> 2 #include

2015湖南省队集训DAY3——Light

Light [问题描述] "若是万一琪露诺(俗称 rhl)进行攻击,什么都好,冷静地回答她的问题来吸引 对方表现出兴趣的话,那就慢慢地反问.在她考虑答案的时候,趁机逃吧.就算是很简 问题,她一定也答不上来." --<上古之魔书> 天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列 a[i],远 魔书上记载到:2 个位置的 graze 值为两者位置差与数值差的和: graze(x,y)=|x-y|+|a[x]-a[y]|. 要想破解天罚,就必须支持 2种操作(

FJ省队集训DAY2 T1

思路:转换成n条三维空间的直线,求最大的集合使得两两有交点. 有两种情况:第一种是以某2条直线为平面,这时候只要统计这个平面上有几条斜率不同的直线就可以了 还有一种是全部交于同一点,这个也只要判断就可以了. 然后我并不能改出来,wa了好多个点 WA的程序: 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm&

bzoj4171 or 省队集训day3 chess: Rhl的游戏

[题目描述] RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色.每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子),黑变白,白变黑. RHL希望把所有格子都变成白色的.不幸的是,有一些格子坏掉了,无法被按下.这时,它可以完成游戏吗? [输入格式] 第一行一个整数T,表示T组数据. 每组数据开始于三个整数n,m,k,分别表示格子的高度和宽度.坏掉格子的个数.接下来的n行,每行一个长度m

FJ省队集训DAY5 T1

思路:考试的时候打了LCT,自以为能过,没想到只能过80.. 考完一想:lct的做法点数是100W,就算是nlogn也会T. 讲一下lct的做法把:首先如果一条边连接的两个点都在同一个联通块内,那么这条边对答案没有影响,可以忽略,因此,问题变成了每次询问两个点中路径上权值最大的边(这里的权值我们令它为加入这条边的时间),边我们用一个点连接两个端点来表示. 正解:由于是无根树,因此我们用并查集按秩合并,每次把小的加到大的里面去,询问的时候暴力走lct查找最大即可. 1 #include<cstdi