国庆摸底测试

考了上下午两场六题,应该是模拟noip的。

第三题过于难,考的奇葩数论。T5T6都简单了些。

得分100 + 100 + 40 + 100 + 0 + 30 = 370

简单分析一下,主要失误在于T5。

三个100就不说,T3尽力了。T6是类似魔法森林的一道题,是个删边维护生成树的套路,没想出来。

T5显然在我的能力范围之内,爆0。

 


大意:一个寂寞堆的性质是:子节点不大于父节点 && 左子树每个点都不大于柚子树。

给你一个满二叉树,问至少改变几个数能使它变成寂寞的。

当时我满脑子都是树形DP,区间DP,但是怎么想都不对...

然后发现可以把每个点之间的关系做成图,不满足的条件作为边,然后跑最小点覆盖。

然后发现这TM不是二分图啊......

然后又去想怎么在这个二叉树上面DP,没搞出来......

然后准备把小数据特判得30分,但是因为我愚蠢的输出了树中节点个数导致这30分也凉了。

正解:注意上面,把每个点的关系做成图。

实际上这个图的拓扑序唯一,因为任意两个点的大小都可以藉由lca得出。

所以按照逆拓扑序求最长不升子序列就OK了。

拓扑序在这里就是中右左序。

 


接着讲一下T6的套路:题意:

给你n个点,q次操作,有加边,删边,查询连通性。

且每两点的边至多只会被加/删一次。

n<=400,q<=100000

解:

考虑暴力,显然是每次DFS。这样做是qm的,m上限有n²,所以是qn²,能拿30分。

然后我们发现这个n很小,有什么用呢?不知道。

然后我们考虑转图为树,那么只需维护生成树即可。

维护哪些生成树呢?删边时间最靠后的!

因为如果走一些删边时间靠前的边能到达,那么这个生成树也一定可达。

如果这个都不可达,那么删边时间靠前的更不可达。

然后,遍历树是n的,于是时间被压到了qn,4e7可以过。

删边的时候如果还在就删。加边的时候,如果连通就去掉删除时间最早的。查询直接DFS。

实际操作上,由于是森林所以不需要vis数组。记录父亲即可。

用vector代替邻接表存边,以节省遍历被删的边的时间,做到O(n)。

  1 #include <cstdio>
  2 #include <vector>
  3 #include <algorithm>
  4 #include <cstring>
  5 
  6 const int N = 405, INF = 0x3f3f3f3f, M = 100010;
  7 
  8 std::vector<int> G[N];
  9 char c[M][10];
 10 int del[N][N], da, db, xx[M], yy[M];
 11 
 12 bool DFS(int x, int t, int f) {
 13     //printf("DFS : x = %d \n", x);
 14     if(x == t) {
 15         return 1;
 16     }
 17     for(int i = 0; i < G[x].size(); i++) {
 18         //printf("G[%d][%d] = %d \n", x, i, G[x][i]);
 19         int y = G[x][i];
 20         if(y != f && DFS(y, t, x)) {
 21             return 1;
 22         }
 23     }
 24     return 0;
 25 }
 26 
 27 bool getmin(int x, int T, int f) {
 28     if(x == T) {
 29         return 1;
 30     }
 31     for(int i = 0; i < G[x].size(); i++) {
 32         int y = G[x][i];
 33         if(y == f) {
 34             continue;
 35         }
 36         int t = getmin(y, T, x);
 37         if(t && (del[x][y] <= del[da][db])) { // error : <
 38             da = x;
 39             db = y;
 40         }
 41         if(t) {
 42             return 1;
 43         }
 44     }
 45     return 0;
 46 }
 47 
 48 int main() {
 49     freopen("fool3.in", "r", stdin);
 50     freopen("my.out", "w", stdout);
 51     int n, m;
 52     scanf("%d%d", &n, &m);
 53     int x, y;
 54     memset(del, 0x3f, sizeof(del));
 55     for(int i = 1; i <= m; i++) {
 56         scanf("%s", c[i]);
 57         scanf("%d%d", &xx[i], &yy[i]);
 58         if(c[i][0] == 'd') {
 59             del[xx[i]][yy[i]] = del[yy[i]][xx[i]] = i;
 60         }
 61     }
 62 
 63     for(int i = 1; i <= m; i++) {
 64         x = xx[i];
 65         y = yy[i];
 66         if(c[i][0] == 'd') { // del
 67             for(int i = 0; i < G[x].size(); i++) {
 68                 if(G[x][i] == y) {
 69                     std::swap(G[x][i], G[x][G[x].size() - 1]);
 70                     G[x].pop_back();
 71                     break;
 72                 }
 73             }
 74             for(int i = 0; i < G[y].size(); i++) {
 75                 if(G[y][i] == x) {
 76                     std::swap(G[y][i], G[y][G[y].size() - 1]);
 77                     G[y].pop_back();
 78                     break;
 79                 }
 80             }
 81         }
 82         else if(c[i][1] == 'd') { // add
 83             getmin(x, y, 0);
 84             if(del[x][y] <= del[da][db]) {
 85                 if(da) {
 86                     da = db = 0;
 87                     continue;
 88                 }
 89                 G[x].push_back(y);
 90                 G[y].push_back(x);
 91                 continue;
 92             }
 93             for(int i = 0; i < G[da].size(); i++) {
 94                 if(G[da][i] == db) {
 95                     std::swap(G[da][i], G[da][G[da].size() - 1]);
 96                     G[da].pop_back();
 97                     break;
 98                 }
 99             }
100             for(int i = 0; i < G[db].size(); i++) {
101                 if(G[db][i] == da) {
102                     std::swap(G[db][i], G[db][G[db].size() - 1]);
103                     G[db].pop_back();
104                     break;
105                 }
106             }
107             da = db = 0;
108             G[x].push_back(y);
109             G[y].push_back(x);
110         }
111         else { // ask
112             printf("%d\n", DFS(x, y, 0));
113         }
114     }
115 
116     return 0;
117 }
AC代码

时间卡的很紧,0.9s过的大数据。可以用LCT优化到qlog²n,那就是魔法森林了。

总结:初级的题没有失误很好;T3,T5这种难度的尽量争取满分,没把握就面向数据,反正部分分一定要拿稳。如果时间还多,暴力又打完了,检查一万遍了,尽量爆肝正解。说不定灵光一闪就A了;不要太自信,对拍是必要的。没有对拍就手造10min的数据。

[update]:T3简直天秀,真·神奇解法,天下第一。

之后填坑。

posted @ 2018-10-02 15:44  garage  阅读(116)  评论(0编辑  收藏  举报