zoukankan      html  css  js  c++  java
  • 2016.7.22.noip2012D2

    mod:

    扩展欧几里德算法,而我没有复习,暴力的60

    事后后悔死

    classroom:

    线段树得90,T两个点。代码与问题如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 using namespace std;
     5 int n,m,s,t;
     6 long long r[1000005],d;
     7 struct stu
     8 {
     9     int l,r;
    10     long long mi,val;
    11 }tree[4000005];
    12 int minn(int q1,int q2)
    13 {
    14     if(q1>q2) return q2;
    15     return q1;
    16 }
    17 void pushdown(int v)
    18 {
    19     if(tree[v].l==tree[v].r) return ;
    20     tree[v<<1].val+=tree[v].val;
    21     tree[(v<<1)+1].val+=tree[v].val;
    22     tree[v<<1].mi-=tree[v].val;//-=忘了,-的只有本次的值也忘了 
    23     tree[(v<<1)+1].mi-=tree[v].val;
    24     tree[v].val=0;
    25 }
    26 void build(int left,int right,int u)
    27 {
    28     tree[u].l=left;
    29     tree[u].r=right;
    30     if(left==right)
    31     {
    32         tree[u].mi=r[left];
    33         return ;
    34     }
    35     int mid=(left+right)>>1;
    36     build(left,mid,u<<1);
    37     build(mid+1,right,(u<<1)+1);
    38     tree[u].mi=minn(tree[u<<1].mi,tree[(u<<1)+1].mi);
    39 }
    40 bool query(int u,int left,int right,long long dd)
    41 {
    42     bool flag;
    43     if(tree[u].l==left&&tree[u].r==right)
    44     {
    45         
    46         if(tree[u].mi>=dd) 
    47         {
    48             tree[u].mi-=dd;
    49             tree[u].val+=dd;
    50             return true;
    51         }
    52         return false;
    53     }
    54     if(tree[u].val) pushdown(u);
    55     int mid=(tree[u].l+tree[u].r)>>1;
    56     if(right<=mid) flag=query(u<<1,left,right,dd);
    57     else if(left>mid) flag=query((u<<1)+1,left,right,dd);
    58     else if(query(u<<1,left,mid,dd)&&query((u<<1)+1,mid+1,right,dd)) flag=true;
    59     else flag=false;
    60     tree[u].mi=minn(tree[u<<1].mi,tree[(u<<1)+1].mi);//向上更新,在合并的时候忘了 
    61     return flag;
    62 }
    63 int main()
    64 {
    65     freopen("classroom.in","r",stdin);
    66     freopen("classroom.out","w",stdout);
    67     scanf("%d %d",&n,&m);
    68     for(int i=1;i<=n;i++)
    69         scanf("%lld",&r[i]);
    70     build(1,n,1);
    71     for(int j=1;j<=m;j++)
    72     {
    73         scanf("%lld %d %d",&d,&s,&t);
    74         if(query(1,s,t,d)==false)
    75         {
    76            printf("-1
    ");
    77            printf("%d
    ",j);
    78            return 0;    
    79         }
    80     }
    81     printf("0
    ");
    82     return 0;
    83 }

    另,正解是二分订单,如下:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int n,m,s[1000005],t[1000005],ans;
    int r[1000005],d[1000005],a[1000005];
    void depart(int l,int ri)
    {
        memset(a,0,sizeof(a));
        bool flag=false;
        if(l==ri)
        {
            return ;
        }
        int midd=(l+ri)>>1;
        int sum=0;
        for(int i=1;i<=midd;i++)
        {
            a[s[i]]+=d[i];
            a[t[i]+1]-=d[i];
        }
        for(int i=1;i<=n;i++)
            {
                sum+=a[i];
                if(sum>r[i])
                {
                   flag=true;    
                   break;
                }    
            }
        
        if(flag){
            ans = midd;
         depart(l,midd);
        }else depart(midd+1,ri);
    }
    int main()
    {
        freopen("classroom.in","r",stdin);
        freopen("classroom.out","w",stdout);
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&r[i]);
        for(int j=1;j<=m;j++)
            scanf("%d %d %d",&d[j],&s[j],&t[j]);
        depart(1,m);
        if(ans)
            {
               printf("-1
    ");
               printf("%d
    ",ans);
               return 0;    
            }
        printf("0
    ");
        return 0;
    }

    blockade:

    惊呆,看标答都看了1小时...借大神的程序配大神的注释与自己的理解。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #define INF 999999999999
    #define LL long long
    #define Max(x,y) if(x<y) x=y;
    #define N 100003
    using namespace std ;
    struct P{
        LL p,t;
        P():p(),t(){}
        P(const LL x,const LL y) : p(x),t(y){}   
    }army[N],edge[N];
    bool cmp(const P &x,const P &y){
        return x.t>y.t; 
    } 
    LL n,m,T;
    LL next[N*2],last[N*2],to[N*2];
    LL w[N*2];
    LL p[N],from[N],root[N];
    LL dis[N],left[N]; 
    bool use[N]; 
    queue<LL> q;
    inline void addedge(LL a,LL b,LL c){//存边的关系 
        next[++T]=last[a]; last[a]=T; to[T]=b ; w[T]=c;
        next[++T]=last[b]; last[b]=T; to[T]=a ; w[T]=c;
    }
    void fail(){//比较军队数和根节点连接的路径数,说白了特判 
        LL Tot=0;
        for(LL i=last[1];i;i=next[i]) ++Tot;
        if(Tot>m) {
            printf("-1");
            exit(0);
        }
    }
    LL pushup(LL now,LL f){//军队移到节点now(now父点是f)剩余的时间。 
         if(!next[last[now]]) {//叶子结点
           if(left[now]>=0ll) use[now]=1 ;//守住now结点 
            return left[now]   ;
         } 
         use[now]=1;//不赋值,有1组数据错;假设可以守住now结点 
         for(LL i=last[now];i;i=next[i]) 
          if(to[i]!=f){//不是父亲节点 
            Max(left[now],pushup(to[i],now)-w[i]);//now的时间选left[now]与下面结点剩的时间中的最大值 
            if(!use[to[i]]) use[now]=0;//now的子结点没守住,则now也可能没守住 
          }
         if(left[now]>=0) use[now]=1;//军队到now结点所剩时间>=0,能管住节点now 
         return left[now];
    }
    bool check(LL lim){
        LL numa=0,numb=0;
        memset(left,-1,sizeof left);//剩余时间 
        memset(use,0,sizeof use);//是否经过 
        memset(from,0,sizeof from);//从哪里来 
        for(LL i=1;i<=m;i++) 
          if(dis[p[i]]>=lim) 
            left[p[i]]=lim;//走不到根1结点,该军队的时限 
          else 
            army[++numa]=P(root[p[i]],lim-dis[p[i]]);//从根1下的root[p[i]]来,生活剩lim-dis[p[i]]时间 
        pushup(1,0);    
        for(LL i=last[1];i;i=next[i]) 
          if(!use[to[i]])
            edge[++numb]=P(to[i],w[i]);
        if(numb>numa) return false; // 军队不够 
        sort(army+1,army+numa+1,cmp);
        sort(edge+1,edge+numb+1,cmp);
        //----来自该节点的所剩时间最少的军队----  
        for(LL i=numa;i;i--)
           if(!from[army[i].p]) 
             from[army[i].p]=i;
        //-------------------------------------- 
        LL la=1,lb=1;
        memset(use,0,sizeof use); //归并,从大到小,有一个不满足就全不满足 
        use[0]=1;
        while(lb<=numb&&la<=numa){
           if(use[la]){
              ++la;
              continue ;    
           }
           if(!use[from[edge[lb].p]]){
              use[from[edge[lb].p]]=1;
              ++lb;
              continue ;
           }
           if(army[la].t<edge[lb].t) return false ;
           use[la]=1;
           ++la ;
           ++lb ; 
        }
        return true ; 
    }
    void prework(){
       q.push(1);//队列 
       use[1]=1;
       for(LL i=last[1];i;i=next[i]) root[to[i]]=to[i];//与1相连的所有点 ,父亲为自己 
       while(!q.empty()){//队列非空 
            LL now=q.front();
            q.pop();
            for(LL i=last[now];i;i=next[i]) 
            if(!use[to[i]]){
                if(now!=1) root[to[i]]=root[now];//记爸爸 
                dis[to[i]]=dis[now]+w[i];//深度 
                use[to[i]]=1;//走没走 
                q.push(to[i]);
            }
       }
    }
    int main(){
        freopen("blockade.in","r",stdin);
        freopen("blockade.out","w",stdout);
        scanf("%I64d",&n);
        LL a,b,c;
        for(LL i=1;i<n;i++){
            scanf("%I64d%I64d%I64d",&a,&b,&c);
            addedge(a,b,c);
        }
        scanf("%I64d",&m);
        fail();
        for(LL i=1;i<=m;i++) scanf("%I64d",&p[i]);
        LL ans,l=0,r=100000000000000LL;//时间范围,尽量取大 
        prework();//广搜预处理 
        while(l<=r){//二分时间 
            LL mid=(l+r)>>1;
            if(check(mid)){
                ans=mid;
                r=mid-1;
            } else l=mid+1;
        }
        printf("%I64d",ans); 
        return 0;   
    }
  • 相关阅读:
    高斯消元学习
    HDU 4596 Yet another end of the world(解一阶不定方程)
    Codeforces Round #318 div2
    HDU 4463 Outlets(一条边固定的最小生成树)
    HDU 4458 Shoot the Airplane(计算几何 判断点是否在n边形内)
    HDU 4112 Break the Chocolate(简单的数学推导)
    HDU 4111 Alice and Bob (博弈)
    POJ 2481 Cows(线段树单点更新)
    HDU 4288 Coder(STL水过)
    zoj 2563 Long Dominoes
  • 原文地址:https://www.cnblogs.com/fisch/p/5697241.html
Copyright © 2011-2022 走看看