洛谷 三月月赛 C

呵呵呵呵,这个sb题做了好久,然并卵,还是不对。

挖坑++

然而我感觉我做的对了,偷瞄了一下题解应该没什么问题。

这个题有n个点,n条边,所以是个基环树(我也不知道是不是这个名)

要每个点有联通,就是一个n个点的环,要是答案最小,那么我们就要保留下一些最大的链

现在我们考虑,因为一个点只有一个入度(n-1条边的话是一个严格从根节点单向向外的树),现在多了一个边,所以多了形成一个环

那先现在这个东西(基环树)就是一个环外面挂着一些严格向外延展的子树。

所以先考虑子树,对于每一个节点,贪心的保留一个权值最大的边连的儿子保留,其他的切掉(这里说的切掉是指重建),(这一步做完之后出来的东西就类似于树链剖分出来的重链)

再来考虑环,与环相连的子树,选择切掉,那么环是不用动的,选择不切,那么在环上对应的下条边是要切掉的。(这里打一个标记,判断切没切,然后,没切的话要找环上最小的边切开)

需要注意的是,可以不止一个基环树233333

  1 #include<bits/stdc++.h>
  2 #define N 100005
  3 #define LL long long
  4 #define inf 1LL<<60
  5 using namespace std;
  6 inline LL ra()
  7 {
  8     LL x=0,f=1; char ch=getchar();
  9     while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
 10     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
 11     return x*f;
 12 }
 13 struct edge{
 14     int to,next; LL v;
 15 }e[N];
 16 int head[N],cnt,n,start,d[N];
 17 int top,ind,q[N],low[N],dfn[N],size[N],num,belong[N];
 18 LL ans,sum,f[N],del,cst[N];
 19 bool vis[N],cut,inq[N],can[N];
 20 void insert(int x, int y, LL v)
 21 {
 22     e[++cnt].next=head[x]; e[cnt].to=y; e[cnt].v=v; head[x]=cnt;
 23 }
 24 void tarjan(int x)
 25 {
 26     dfn[x]=low[x]=++ind;
 27     q[++top]=x; inq[x]=1;
 28     for (int i=head[x];i;i=e[i].next)
 29         if (!dfn[e[i].to])
 30         {
 31             tarjan(e[i].to);
 32             low[x]=min(low[e[i].to],low[x]);
 33         }
 34         else if (inq[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
 35     if (low[x]==dfn[x])
 36     {
 37         ++num;
 38         int now=-1;
 39         while (now!=x)
 40         {
 41             now=q[top--];
 42             belong[now]=num;
 43             size[num]++;
 44             inq[now]=0;
 45         }
 46     }
 47 }
 48 void get_cost(int x)
 49 {
 50     can[x]=1;
 51     for (int i=head[x];i;i=e[i].next)
 52     {
 53         if (vis[e[i].to]) cst[x]=e[i].v;
 54         if (e[i].to==start || !vis[e[i].to]) continue;
 55         get_cost(e[i].to);
 56     }
 57 }
 58 void solve_son(int x)
 59 {
 60     LL son_sum=0,son_mx=0;
 61     for (int i=head[x];i;i=e[i].next)
 62     {
 63         son_sum+=e[i].v,son_mx=max(son_mx,e[i].v);
 64         f[x]+=f[e[i].to];
 65         solve_son(e[i].to);
 66     }
 67     f[x]+=son_sum-son_mx;
 68 }
 69 void dfs(int x)
 70 {
 71     LL son_del=-inf; can[x]=1;
 72     for (int i=head[x];i;i=e[i].next)
 73     {
 74         son_del=max(son_del,-cst[x]);
 75         if (e[i].to==start) continue;
 76         if (vis[e[i].to]) dfs(e[i].to);
 77         else
 78         {
 79             solve_son(e[i].to);
 80             ans+=f[e[i].to]+e[i].v;
 81             son_del=max(son_del,e[i].v-cst[x]);
 82         }
 83     }
 84     if (son_del>0) cut=1,ans-=son_del; else del=max(del,son_del);
 85 }
 86 int main()
 87 {
 88     n=ra();
 89     for (int i=1; i<=n; i++) 
 90     {
 91         int x=ra();
 92         LL v=(LL)ra();
 93         if (x==i) ans+=v; else insert(x,i,v);
 94     }
 95     for (int i=1; i<=n; i++) 
 96         if (!dfn[i]) tarjan(i);
 97     int hehe=0;
 98     bool flag=0;
 99     for (int i=1; i<=n; i++)
100         if (size[belong[i]]>1) 
101         {
102             if (hehe && hehe!=belong[i]) flag=1;
103             hehe=belong[i];
104             vis[i]=1;
105         }
106     for (int i=1; i<=n; i++)
107         if (!vis[i]) {flag=1; break;}
108     if (!flag)
109     {
110         cout<<"0"<<endl;
111         return 0;
112     }
113     for (int i=1; i<=n; i++)
114         if (vis[i] && !can[i])
115         {
116             start=i;
117             get_cost(i);
118         }
119     memset(can,0,sizeof(can));
120     for (int i=1; i<=n; i++)
121         if (vis[i] && !can[i])
122         {
123             cut=0; del=-inf;
124             start=i; dfs(i);
125             if (!cut) ans-=del;
126         }
127 //    for (int i=1; i<=n; i++) printf("%d ",f[i]);
128     cout<<ans<<endl;
129     return 0;
130 }

 

posted @ 2017-03-13 21:21  ws_ccd  阅读(137)  评论(0编辑  收藏  举报