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;   
}
原文地址:https://www.cnblogs.com/fisch/p/5697241.html