HNOI 2016 省队集训日记

第一天


DeepDarkFantasy

从东京出发,不久便到一处驿站,写道:日暮里。  ——鲁迅《藤野先生》

定义一个置换的平方为对1~n的序列做两次该置换得到的序列。已知一个置换的平方,并且这个结果是一个排列,求该置换。

输入第一行一个数n表示排列长度,接下来一行n个数描述排列。

有解则输出一行n个数表示原排列。否则输出一行一个-1。

 

测试点编号

特征

0~1

n<=10

2~9

n<=1000000

此题有spj。


  考试的时候懵逼了,根本没想清就开始乱打。

  题解:由题易得每一个置换相当于一个n个点n条边的图,那么相当于是已知每个点在图上走两步的终点,求这个图。于是我们可以很快的得到,无论图中的环是奇环还是偶环,最终得到的答案都会是偶环。然后对于两种不同的情况分类讨论一下就可以得到解法了。

  代码写丑了,虽然是O(N)的,但因为常数问题没能过。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 using namespace std;
 6 const int maxn=1000010;
 7 int a[maxn],num[maxn];
 8 int ans[maxn],p[maxn];
 9 int b[maxn],n;
10 int st[maxn],top;
11 int vis[maxn],c[maxn];
12 bool cmp(int x,int y){
13     return num[x]<num[y];
14 }
15 
16 int main(){
17 #ifndef ONLINE_JUDGE
18     freopen("deepdarkfantasy.in","r",stdin);
19     freopen("deepdarkfantasy.out","w",stdout);
20 #endif
21     scanf("%d",&n);
22     for(int i=1,x;i<=n;i++){
23         scanf("%d",&x);
24         a[x]=i;p[i]=i;
25     }
26     int x,y,t,q,tot;
27     for(int i=1;i<=n;i++){
28         if(a[i]==i){
29             b[i]=i;
30             continue;
31         }
32         if(!vis[i]){
33             x=i,tot=0;
34             while(!vis[x]){
35                 tot+=1;
36                 vis[x]=1;
37                 x=a[x];
38             }
39             st[++top]=x;
40             num[top]=tot;
41             c[tot]+=1;
42         }
43     }
44     for(int i=1;i<=n;i++)
45         if(i%2==0&&c[i]%2){
46             printf("-1
");
47             return 0;
48         }
49     sort(p+1,p+top+1,cmp);
50     for(int i=1;i<=top;i++){
51         x=p[i],t=st[x];
52         if(num[x]%2){
53             for(int j=1,k=1;j<=num[x];j++){
54                 ans[k]=t;
55                 t=a[t];k+=2;
56                 if(k>num[x])k=2;
57             }
58             ans[0]=ans[num[x]];
59             for(int j=1;j<=num[x];j++)
60                 b[ans[j-1]]=ans[j];
61         }
62         else{
63             y=p[++i],q=st[y];
64             for(int j=1;j<=2*num[x];j++){
65                 if(j%2){
66                     ans[j]=t;
67                     t=a[t];
68                 }
69                 else{
70                     ans[j]=q;
71                     q=a[q];
72                 }
73             }
74             ans[0]=ans[2*num[x]];
75             for(int j=1;j<=2*num[x];j++)
76                 b[ans[j-1]]=ans[j];
77         }
78     }
79     for(int i=1;i<=n;i++)
80         printf("%d ",b[i]);
81     printf("
");    
82     return 0;    
83 }

Wallace

 

“看来华莱士先生不太懂历史和哲♂学”  ——自长者与美国记者华莱士的谈话

有两颗各含N个点的无根树,每棵树中点分别被编号为0,1,2,....,N-1;注意两棵树并不保证同构。另外给一个N长的整数数组Score[],记录N个编号的得分,Score中的每个元素可正可负。问题的任务是寻找 集合{0,1,2,3,4,...,N-1}的一个最优子集subset(可以是空集),要求满足以下条件:

1)在第一棵树中,subset中包含的编号对应的点能构成一个连通的子图;即去掉这棵树中所有subset中不包含的点后,剩下的点依然是一棵连通的树。

2)在第二棵树中,subset中包含的编号对应的点也能构成一个连通的子图;

3)使subset包含编号的总得分尽可能的大;即SUM{ Score[i] | i∈subset }能取到尽可能大的值。

输入第一行一个正整数N。第二行N个整数Score[]代表0~N-1每个点的权值。

后面N-1行每行两个整数u,v代表第一棵树里面u点和v点之间有连边。

再后面N-1行每行两个整数u,v代表第二棵树里面u点和v点之间有连边。

输出一行一个整数代表这个subset包含编号的总分的最大值。

 

测试点编号

特征

0~5

n<=15

6~9

两棵树形状与编号完全相同

12~24

2<=n<=50且|Score[i]|<=1000且0<=u,v<n

  这道题并不是很难,枚举一个点必选,则可以用网络流做。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 using namespace std;
  6 
  7 const int maxn=510;
  8 const int maxm=1000010;
  9 const int INF=100000000;
 10 int cnt,tot,fir[maxn],fron[maxn],dis[maxn];
 11 int to[maxm],nxt[maxm],gap[maxn],path[maxn];
 12 int cap[maxm];queue<int>q;
 13 
 14 struct Max_Flow{
 15     void Init(int tot_=0){
 16         tot=tot_;cnt=1;
 17         memset(fir,0,sizeof(fir));
 18         memset(dis,0,sizeof(dis));
 19         memset(gap,0,sizeof(gap));
 20     }
 21     
 22     void add(int a,int b,int c){
 23         nxt[++cnt]=fir[a];
 24         fir[a]=cnt;
 25         cap[cnt]=c;
 26         to[cnt]=b;
 27     }
 28     
 29     void addedge(int a,int b,int c){
 30         add(a,b,c);
 31         add(b,a,0);
 32     }
 33     
 34     bool BFS(int s,int t){
 35         dis[t]=1;q.push(t);
 36         while(!q.empty()){
 37             int x=q.front();q.pop();
 38             for(int i=fir[x];i;i=nxt[i])
 39                 if(!dis[to[i]]){
 40                     dis[to[i]]=dis[x]+1;
 41                     q.push(to[i]);
 42                 }
 43         }
 44         return dis[s];
 45     }
 46     
 47     int Aug(int s,int t,int &p){
 48         int f=INF;
 49         while(p!=s){
 50             f=min(f,cap[path[p]]);
 51             p=to[path[p]^1];
 52         }p=t;
 53         while(p!=s){
 54             cap[path[p]]-=f;
 55             cap[path[p]^1]+=f;
 56             p=to[path[p]^1];
 57         }
 58         return f;
 59     }
 60     
 61     int ISAP(int s,int t){
 62         if(!BFS(s,t))return 0;
 63         for(int i=s;i<=t;i++)fron[i]=fir[i];
 64         for(int i=s;i<=t;i++)gap[dis[i]]+=1;
 65         int p=s,ret=0;
 66         while(dis[s]<=tot){
 67             if(p==t)ret+=Aug(s,t,p);
 68             
 69             for(int &i=fron[p];i;i=nxt[i])
 70                 if(cap[i]&&dis[p]==dis[to[i]]+1){
 71                     path[p=to[i]]=i;
 72                     break;
 73                 }
 74             
 75             if(!fron[p]){
 76                 if(--gap[dis[p]]==0)
 77                     break;
 78                 int Min=tot;
 79                 for(int i=fir[p];i;i=nxt[i])
 80                     if(cap[i])Min=min(Min,dis[to[i]]);
 81                 gap[dis[p]=Min+1]+=1;fron[p]=fir[p];
 82                 if(p!=s)p=to[path[p]^1];    
 83             }    
 84         }
 85         return ret;
 86     }
 87 }isap;
 88 
 89 int w[maxn],n;
 90 int G[maxn][maxn];
 91 int G2[maxn][maxn];
 92 int dep[maxn],pre[maxn];
 93 
 94 void Build(int x,int y){
 95     int py=y;
 96     while(x!=py){
 97         if(dep[x]>dep[py]){
 98             x=pre[x];
 99             isap.addedge(y,x,INF);
100         }
101         else{
102             py=pre[py];
103             isap.addedge(y,py,INF);
104         }
105     }
106 }
107 
108 int DFS(int x,int fa){
109     int ret=0;
110     if(w[x]>=0){
111         isap.addedge(0,x,w[x]);
112         ret+=w[x];
113     }
114     else isap.addedge(x,n+1,-w[x]);
115     for(int i=1;i<=n;i++)
116         if(G[x][i]&&i!=fa){
117             isap.addedge(i,x,INF);
118             Build(x,i);ret+=DFS(i,x);
119         }
120     return ret;    
121 }
122 
123 void Prepare(int x,int fa){
124     for(int i=1;i<=n;i++)
125         if(G2[x][i]&&i!=fa){
126             dep[i]=dep[x]+1;
127             pre[i]=x;Prepare(i,x);
128         }
129 }
130 
131 int main(){
132     freopen("wallace.in","r",stdin);
133     freopen("wallace.out","w",stdout);
134     scanf("%d",&n);
135     for(int i=1;i<=n;i++)
136         scanf("%d",&w[i]);
137     for(int i=1,a,b;i<n;i++){
138         scanf("%d%d",&a,&b);
139         G[a+1][b+1]=G[b+1][a+1]=1;
140     }
141     for(int i=1,a,b;i<n;i++){
142         scanf("%d%d",&a,&b);
143         G2[a+1][b+1]=G2[b+1][a+1]=1;
144     }Prepare(1,0);
145     int ans=0,tmp;
146     for(int i=1;i<=n;i++){
147         isap.Init(n+2);tmp=DFS(i,0);
148         ans=max(ans,tmp-isap.ISAP(0,n+1));
149     }
150     printf("%d
",ans);
151     return 0;    
152 }

第二天


永不落幕的 永不落幕的 zy
【背景】
人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。
【题目 描述】 描述】
zy 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 sm 是一位 是一位 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 zy (的 能力)就是为了 能力)就是为了 能力)就是为了 能力)就是为了 sm 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。
sm 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 X轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 zy 能 消除 sm 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, zy 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。
假设现在时间是 假设现在时间是 假设现在时间是 假设现在时间是 0,zy 在心墙的 在心墙的 在心墙的 1位置, 位置, zy 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 1。
若现在 若现在 zy 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 边,则 边,则 zy 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 sm 没有任何迷茫,则 没有任何迷茫,则 没有任何迷茫,则 没有任何迷茫,则 没有任何迷茫,则 zy 原地不动。现在 原地不动。现在 原地不动。现在 原地不动。现在 zy 想 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。
为了尽快地让 为了尽快地让 为了尽快地让 zy 能拥抱 能拥抱 sm ,请你帮他。 ,请你帮他。 ,请你帮他。 ,请你帮他。
【输入描述】 【输入描述】
第一行两个数 第一行两个数 第一行两个数 N,M表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 N行 ,每行 ,每行 ,每3个整 数, t, a,b,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 t,希望从 ,希望从 a到 b。
【输出描述】 【输出描述】
N行 N个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失
【样例输入】 【样例输入】
2 102 102 102 10
1 2 51 2 51 2 51 2 5
7 4 57 4 57 4 57 4 5
【样例输出】 【样例输出】
5
9
【样例解释】 【样例解释】
时刻 1,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了!
时刻 2,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 2。
时刻 5,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 5,迷茫消失。 ,迷茫消失。 ,迷茫消失。
时刻 7,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了!
时刻 8,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 4。
时刻 9,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 5,迷茫消失。 ,迷茫消失。 ,迷茫消失。
【数据范围】 【数据范围】
对于 30%30%30%的数据 的数据 : N, M, t <= 100t <= 100 t <= 100t <= 100 t <= 100t <= 100
对于 60%60%60%的数据 的数据 : N, M, t <= N, M, t <= N, M, t <= N, M, t <= N, M, t <= N, M, t <= 1000010000100001000010000
对于 100%100%100%100%的数据 的数据 : N, M, t <= 100000 N, M, t <= 100000 N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000 N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000N,


  这么长的题面,呵呵了。

  发现如果每次处理一个迷惘,则只有O(N)次操作,考虑将每次的复杂度降为log2N。

  这里用的treap。

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 using namespace std;
  7 const int maxn=200010;
  8 const long long INF=10000000000000000LL;
  9 struct Node{
 10     long long t,a,b;
 11     int id,tp;
 12     Node(long long t_=0,long long a_=0,long long b_=0,int id_=0,int tp_=0){
 13         t=t_;a=a_;b=b_;id=id_;tp=tp_;
 14     }
 15 }px[maxn],t[maxn];
 16 
 17 bool cmp(Node x,Node y){
 18     return x.t<y.t; 
 19 }
 20 
 21 int cnt;
 22 int sz[maxn],rt;
 23 int ch[maxn][2];
 24 void Push_up(int x){
 25     sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
 26 }
 27 
 28 int Newnode(Node x){
 29     sz[++cnt]=1;t[cnt]=x;
 30     ch[cnt][0]=ch[cnt][1]=0;
 31     return cnt;
 32 }
 33 
 34 int Merge(int x,int y){
 35     if(!x||!y)return x|y;
 36     if(rand()%2){
 37         ch[x][1]=Merge(ch[x][1],y);
 38         Push_up(x);return x;
 39     }
 40     else{
 41         ch[y][0]=Merge(x,ch[y][0]);
 42         Push_up(y);return y;
 43     }
 44 }
 45 
 46 int ta,tb;
 47 void Split(int p,long long k){
 48     if(p==0)return;
 49     if(k==sz[ch[p][0]]+1){
 50         ta=ch[p][0];tb=p;
 51         ch[p][0]=0;Push_up(p);
 52         return;
 53     }
 54     if(k<sz[ch[p][0]]+1){
 55         Split(ch[p][0],k);
 56         ch[p][0]=tb;tb=p;
 57         Push_up(p);
 58     }
 59     else{
 60         k-=sz[ch[p][0]]+1;
 61         Split(ch[p][1],k);
 62         ch[p][1]=ta;ta=p;
 63         Push_up(p);
 64     }
 65 }
 66 
 67 int tx,ty,tz;
 68 void Get_div(int l,int r){
 69     Split(rt,r+1);ty=ta;tz=tb;
 70     Split(ty,l);tx=ta;ty=tb;
 71 }
 72 
 73 void Get_mer(){
 74     tx=Merge(tx,ty);
 75     rt=Merge(tx,tz);
 76 }
 77 
 78 int ID,POS;
 79 void Get_Prev(long long k){
 80     int p=rt,num=0;
 81     while(p){
 82         if(t[p].a<=k){
 83             ID=p;num+=sz[ch[p][0]]+1;
 84             POS=num;p=ch[p][1];
 85         }
 86         else p=ch[p][0];
 87     }
 88     return;
 89 }
 90 
 91 void Get_Succ(long long k){
 92     int p=rt,num=0;
 93     while(p){
 94         if(t[p].a<k){
 95             num+=sz[ch[p][0]]+1;
 96             p=ch[p][1];
 97         }
 98         else{
 99             ID=p;POS=num+sz[ch[p][0]]+1;
100             p=ch[p][0];
101         }
102     }
103     return;    
104 }
105 
106 //严格小于x的个数 
107 long long Get_Min(long long x){
108     Get_Succ(x);
109     return POS-1;
110 }
111 
112 void Insert(Node x){
113     Get_Prev(x.a);
114     Split(rt,POS+1);
115     ta=Merge(ta,Newnode(x));
116     rt=Merge(ta,tb);
117 }
118 
119 void Delete(int p){
120     Get_div(p,p);
121     rt=Merge(tx,tz);
122 }
123 
124 int n,m;
125 long long nt=0,np=1;
126 int Get_Tow(){
127     long long Min=Get_Min(np);
128     long long Max=sz[rt]-Min;
129     return Min<=Max?1:-1;
130 }
131 
132 void Init(){
133     rt=Newnode(Node(0,-1,0,0,0));
134     rt=Merge(rt,Newnode(Node(0,INF,0,0,0)));
135 }
136 
137 
138 void Print(long long p){
139     if(!p)return;
140     Print(ch[p][0]);
141     printf("%lld ",t[p].a);
142     Print(ch[p][1]);
143 }
144 
145 void Debug(){
146     printf("~~~~~~~~~~~~~~~~~
");
147     Print(rt);
148     printf("
~~~~~~~~~~~~~~~~~
");
149 }
150 
151 
152 long long ans[maxn];
153 int main(){
154     freopen("sm.in","r",stdin);
155     freopen("sm.out","w",stdout);
156     Init();
157     scanf("%d%d",&n,&m);srand(n);
158     for(int i=1;i<=n;i++){
159         long long t,a,b;
160         scanf("%lld%lld%lld",&t,&a,&b);
161         px[i]=Node(t,a,b,i,0);
162     }
163     sort(px+1,px+n+1,cmp);
164     for(int i=1;i<=n;i++){
165         while(sz[rt]>2){
166             int tow=Get_Tow();
167             if(tow==1){
168                 Get_Succ(np);
169                 if(nt+t[ID].a-np>=px[i].t){
170                     np+=px[i].t-nt;
171                     break;
172                 }
173                 nt+=t[ID].a-np;
174                 np=t[ID].a;
175                 Delete(POS);
176                 if(t[ID].tp==0)
177                     Insert(Node(0,t[ID].b,0,t[ID].id,1));
178                 else
179                     ans[t[ID].id]=nt;    
180             }
181             else{
182                 Get_Prev(np);
183                 if(nt+np-t[ID].a>=px[i].t){
184                     np-=px[i].t-nt;
185                     break;
186                 }
187                 nt+=np-t[ID].a;
188                 np=t[ID].a;
189                 Delete(POS);
190                 if(t[ID].tp==0)
191                     Insert(Node(0,t[ID].b,0,t[ID].id,1));
192                 else
193                     ans[t[ID].id]=nt;
194             }
195         }
196         Insert(px[i]);
197         nt=px[i].t;
198         //Debug();    
199     }
200     while(sz[rt]>2){
201         int tow=Get_Tow();
202         if(tow==1){
203             Get_Succ(np);
204             nt+=t[ID].a-np;
205             np=t[ID].a;
206             Delete(POS);
207             if(t[ID].tp==0)
208                 Insert(Node(0,t[ID].b,0,t[ID].id,1));
209             else
210                 ans[t[ID].id]=nt;    
211         }
212         else{
213             Get_Prev(np);
214             nt+=np-t[ID].a;
215             np=t[ID].a;
216             Delete(POS);
217             if(t[ID].tp==0)
218                 Insert(Node(0,t[ID].b,0,t[ID].id,1));
219             else
220                 ans[t[ID].id]=nt;
221         }
222     }
223     for(int i=1;i<=n;i++)
224         printf("%lld
",ans[i]);
225     return 0;
226 }

第三天

博士的选取器(Selector.cpp)
【题目描述】
浏览到好图好句的时候,为了避免被删帖、封图、和谐,博士会掏出他的选取器,将好图好句框住,然后Ctrl+C,Ctrl+V。博士从初一开始坚持到现在,已经有2GB了。在反复地与吧主斗争之后,博士总结出了经验。
1).对于一篇帖子,可以从上至下分成N个片段,每个片段不可分割,且只有序号相邻的片段才相邻。
2).每次框选只能框选连续一段片段[L,R],而且这连续一段片段的总字符量不能超过LIMIT,否则会出错。
3).对于每次框选与复制,耗时只与这连续一段片段中字符量最大的那一个片段有关,而且满足正比例函数关系。为了让题目简单,规定耗时等于字符量。
4).两次框选之间的时间间隔可以视为0。
正在博士总结完经验的时候,他瞅到了一篇掺杂大量好图好句的帖子。于是,一场新的战争爆发了…………战局紧张,博士想知道他的最小耗时是多少。
【输入】
第一行两个整数N和Limit。
接下来的N行,每行一个整数,代表第I个片段的字符量
【输出】
仅一行,为博士的最小耗时。
【样例】
Sample Input (Selector.in)
Sample Output (Selector.out)
8 17
2
2
2
8
1
8
2
1
12
{解释:222/818/21,2+8+2=12}
【数据范围】
40%的数据N<=1000
100%的数据N<=300000

这个代码被卡常,无力吐槽,比时限长了0.05S左右,TM还是稳定的。

别人再带一个单调栈复杂度的,线段树优化一下照样踩我程序,QAQ……


  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 using namespace std;
  6 const int maxn=300010;
  7 const long long INF=1000000000000000LL;
  8 int a[maxn];
  9 long long sum[maxn],dp[maxn];
 10 long long tx[maxn*4],ty[maxn*4],tz[maxn*4],tw[maxn*4];
 11 
 12 void Push_down(int x){
 13     if(ty[x]==INF)return;
 14     ty[x<<1]=ty[x];
 15     ty[x<<1|1]=ty[x];
 16     tz[x<<1]=tx[x<<1]+ty[x];
 17     tz[x<<1|1]=tx[x<<1|1]+ty[x];
 18     ty[x]=INF;
 19 }
 20 
 21 void Push_up(int x){
 22     tx[x]=min(tx[x<<1],tx[x<<1|1]);
 23     tz[x]=min(tz[x<<1],tz[x<<1|1]);
 24 }
 25 
 26 void Update(int x,int l,int r,int a,int b,int m){
 27     if(a>b)return;
 28     if(l>=a&&r<=b){
 29         ty[x]=m;
 30         tz[x]=m+tx[x];
 31         return;
 32     }
 33     Push_down(x);
 34     if(l+r>>1>=a)Update(x<<1,l,l+r>>1,a,b,m);
 35     if(l+r>>1<b)Update(x<<1|1,(l+r>>1)+1,r,a,b,m);
 36     Push_up(x);
 37 }
 38 
 39 void Insert(int x,int l,int r,int g){
 40     if(l==r){
 41         tx[x]=dp[l];
 42         ty[x]=INF;
 43         return;
 44     }Push_down(x);
 45     if(l+r>>1>=g)Insert(x<<1,l,l+r>>1,g);
 46     else Insert(x<<1|1,(l+r>>1)+1,r,g);
 47     Push_up(x);
 48 }
 49 
 50 long long Query(int x,int l,int r,int a,int b){
 51     if(a>b)return INF;
 52     if(l>=a&&r<=b)return tz[x];
 53     Push_down(x);
 54     long long ret=INF;
 55     int mid=(l+r)>>1;
 56     if(mid>=a)
 57         ret=Query(x<<1,l,mid,a,b);
 58     if(mid<b)
 59         ret=min(ret,Query(x<<1|1,mid+1,r,a,b));
 60     return ret;
 61 }
 62 
 63 void Insert2(int x,int l,int r,int g){
 64     if(l==r){
 65         tw[x]=a[l];
 66         return;
 67     }
 68     if(l+r>>1>=g)Insert2(x<<1,l,l+r>>1,g);
 69     else Insert2(x<<1|1,(l+r>>1)+1,r,g);
 70     tw[x]=max(tw[x<<1],tw[x<<1|1]);
 71 }
 72 
 73 int Q(int x,int l,int r,long long g){
 74     if(l==r)return l;
 75     if(tw[x<<1|1]<g)
 76         return Q(x<<1,l,l+r>>1,g);
 77     else    
 78         return Q(x<<1|1,(l+r>>1)+1,r,g);
 79 }
 80 int n,lim;
 81 int main(){
 82     freopen("Selector.in","r",stdin);
 83     freopen("Selector.out","w",stdout);
 84     scanf("%d%d",&n,&lim);
 85     for(int i=1;i<=n;i++){
 86         scanf("%d",&a[i]);
 87         sum[i]=sum[i-1]+a[i];
 88     }
 89     int Max0=0;
 90     memset(tx,63,sizeof(tx));
 91     memset(dp,63,sizeof(dp));
 92     int p=0;
 93     for(int i=1;i<=n;i++){
 94         while(sum[i]-lim>sum[p])p+=1;
 95         if(p==0){
 96             Max0=max(Max0,a[i]);
 97             dp[i]=Max0;p+=1;
 98         }
 99         int q=Q(1,1,n,a[i]);
100         Insert2(1,1,n,i);
101         Update(1,1,n,q,i-1,a[i]);
102         dp[i]=min(dp[i],Query(1,1,n,p,i-1));
103         Insert(1,1,n,i);
104         if(p==1&&sum[i]<=lim)p=0;
105     }
106     printf("%lld
",dp[n]);
107     return 0;
108 }
原文地址:https://www.cnblogs.com/TenderRun/p/5668159.html