• 洛谷 三月月赛 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 }
  • 相关阅读:
    JAVA闰年测试与解决非法输入
    Junit介绍与实现
    等价类划分方法的应用
    使用Visual Studio 2013进行UI自动化测试
    简谈软件测试
    【Software Project Management】Quizs
    White box testing
    peer review
    闰年问题
    热烈庆贺清明小长假的到来
  • 原文地址:https://www.cnblogs.com/ccd2333/p/6545124.html
Copyright © 2020-2023  润新知