• bzoj 3669 [Noi2014]魔法森林


    [Noi2014]魔法森林

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 3078  Solved: 1944
    [Submit][Status][Discuss]

    Description

    为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。

    魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小E可以借助它们的力量,达到自己的目的。

    只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。

    由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。

    Input

    第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。

    Output

    输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。

    Sample Input

    【输入样例1】
    4 5
    1 2 19 1
    2 3 8 12
    2 4 12 15
    1 3 17 8
    3 4 1 17
     
    题解:
      这道题目就是先按a排序,然后不断加入b,每次加入的边有可能使得b更小,但是不可能使得a更小
      所以更新答案的a一定是当前加入边的a,然后找1-n最大的b即可,然后lct维护即可,模仿着hzw写的。
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<cstring>
      6 
      7 #define inf 1000000000
      8 #define N 200007 
      9 using namespace std;
     10 int read()
     11 {
     12     int x=0,f=1;char ch=getchar();
     13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     14     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     15     return x*f;
     16 }
     17 int top,q[N];
     18 int n,m,ans=inf;
     19 int mx[N],val[N];
     20 int p[N],fa[N],c[N][2];
     21 bool rev[N];
     22 struct data
     23 {
     24     int u,v,a,b;       
     25 }e[N];
     26 
     27 int find(int x){return x==p[x]?x:p[x]=find(p[x]);}
     28 bool operator<(data a,data b){return a.a<b.a;}
     29 bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
     30 void update(int x)
     31 {
     32     int l=c[x][0],r=c[x][1];
     33     mx[x]=x;
     34     if(val[mx[l]]>val[mx[x]])mx[x]=mx[l];
     35     if(val[mx[r]]>val[mx[x]])mx[x]=mx[r];
     36 }
     37 void pushdown(int x)
     38 {
     39      int l=c[x][0],r=c[x][1];
     40      if(rev[x])
     41      {
     42          rev[x]^=1;rev[l]^=1;rev[r]^=1;
     43          swap(c[x][0],c[x][1]);
     44      }
     45 }
     46 void rotate(int &x)
     47 {
     48      int y=fa[x],z=fa[y],l,r;
     49      if(c[y][0]==x)l=0;else l=1;r=l^1;
     50      if(!isroot(y))
     51      {
     52          if(c[z][0]==y)c[z][0]=x;
     53          else c[z][1]=x;
     54      }
     55      fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
     56      c[y][l]=c[x][r];c[x][r]=y;
     57      update(y);update(x);
     58 }
     59 void splay(int &x)
     60 {
     61      top=0;q[++top]=x;
     62      for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
     63      while(top)pushdown(q[top--]);
     64      while(!isroot(x))
     65      {
     66          int y=fa[x],z=fa[y];
     67          if(!isroot(y))
     68          {
     69              if(c[y][0]==x^c[z][0]==y)rotate(x);
     70              else rotate(y);
     71          }
     72          rotate(x);
     73      }
     74 }
     75 void access(int x)
     76 {
     77     for(int t=0;x;t=x,x=fa[x])
     78         splay(x),c[x][1]=t,update(x);
     79 }
     80 void makeroot(int x)
     81 {
     82      access(x);splay(x);rev[x]^=1;
     83 }
     84 void link(int x,int y)
     85 {
     86     makeroot(x);fa[x]=y;
     87 }
     88 void cut(int x,int y)
     89 {
     90     makeroot(x);access(y);splay(y);
     91     c[y][0]=fa[x]=0;update(y);
     92 }
     93 int query(int x,int y)
     94 {
     95     makeroot(x);access(y);splay(y);
     96     return mx[y]; 
     97 }
     98 int main()
     99 {
    100     n=read();m=read();
    101     for(int i=1;i<=n;i++)p[i]=i;
    102     for(int i=1;i<=m;i++)
    103         e[i].u=read(),e[i].v=read(),e[i].a=read(),e[i].b=read();
    104     sort(e+1,e+m+1);
    105     int tot=0;
    106     for(int i=1;i<=m;i++)
    107     {
    108         int u=e[i].u,v=e[i].v,a=e[i].a,b=e[i].b;
    109         if(find(u)==find(v))
    110         {
    111              int t=query(u,v);
    112              if(val[t]>e[i].b)
    113              {
    114                  cut(t,e[t-n].u);
    115                  cut(t,e[t-n].v);
    116              }
    117              else 
    118              {
    119                  if(find(1)==find(n))ans=min(ans,e[i].a+val[query(1,n)]);
    120                  continue;
    121              }
    122         }
    123         else p[find(u)]=find(v);
    124         val[n+i]=e[i].b;mx[n+i]=n+i;
    125         link(u,n+i);link(v,n+i);
    126         if(find(1)==find(n))ans=min(ans,e[i].a+val[query(1,n)]);
    127     }
    128     if(ans==inf)puts("-1");
    129     else printf("%d
    ",ans);
    130 }
  • 相关阅读:
    A、B、C、D四个字母,能组成多少个互不相同且无重复三位组合
    一对老耗子,每个月都生一对小耗子。小耗子长3个月,第四个开始变成老耗子开始生! 假如都不死,那么请问24个月后有多少只耗子?
    猜数字大小游戏,用户输入一个数字,如果大了就显示大了,如果小了就显示小了, 如果对了就提示正确(补充难度,只有5次机会,限制数字的范围在百位以内)
    输出100-300中的任意两个数相同的三位数(不能三个数都相同)
    打印出A到Z的所有字符,使用char和int转换
    EmployeeMapper.xml例子,学习佟刚老师的myBatis课程,记录下的EmployeeMapper.xml,注释详细
    log4j.xml 精选的log4j.xml文档,比较详细,网上的版本很多,这个版本相对而言比较完整
    Win-Lin双系统重装Windows找回Linux启动
    素材下载网站
    Android系统备忘1
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8082371.html
Copyright © 2020-2023  润新知