• 2019牛客多校第三场


    2019牛客多校第三场

    A. Graph Games

    upsolved

    (n)个点,(m)条边的图((1<=n<=1e5,1<=m,q<=2e5))(q)次操作,操作有两种,一种是翻转区间内边的状态,第二种是询问两个点的邻接点集是否一致

    直接判断点集肯定(T)飞了,给每个点随机一个权值,点集的权值就是全部异或起来,冲突概率很小

    对线段分块,复杂度可以达到(O(qsqrt m))(代码里快读删了)

    #include <bits/stdc++.h>
    using namespace std;
     
    const int N = 1e5 + 10, M = 2e5 + 10, sz = 510;
     
    long long val[N], s[N], sum[sz][N];
    int l[sz], r[sz], belong[M];
    int u[M], v[M], lazy[sz];
    int T, n, m, q, op, blk, num, x, y;
     
    void build() {
        blk = sqrt(m);
        num = 1 + (m - 1) / blk;
        for(int i = 1; i <= num; ++i) {
            l[i] = (i - 1) * blk + 1;
            r[i] = i * blk;
            lazy[i] = 0;
            for(int j = 1; j <= n; ++j)
                sum[i][j] = 0;
        }
        r[num] = m;
        for(int i = 1; i <= m; ++i)
            belong[i] = (i - 1) / blk + 1;
        for(int i = 1; i <= n; ++i)
            s[i] = 0;
    }
     
    void update(int l, int r) {
        if(belong[l] == belong[r]) {
            for(int i = l; i <= r; ++i) {
                s[u[i]] ^= val[v[i]];
                s[v[i]] ^= val[u[i]];
            }
            return;
        }
        for(int i = l; belong[i] == belong[l]; ++i) {
            s[u[i]] ^= val[v[i]];
            s[v[i]] ^= val[u[i]];
        }
        for(int i = r; belong[i] == belong[r]; --i) {
            s[u[i]] ^= val[v[i]];
            s[v[i]] ^= val[u[i]];
        }
        for(int i = belong[l] + 1; i < belong[r]; ++i)
            lazy[i] ^= 1;
    }
     
    int main() {
        srand(time(NULL));
        for(int i = 1; i <= 100000; ++i) val[i] = 1 + rand();
        read(T);
        while(T--) {
            read(n); read(m);
            build();
            for(int i = 1; i <= m; ++i) {
                read(u[i]); read(v[i]);
                s[u[i]] ^= val[v[i]];
                s[v[i]] ^= val[u[i]];
                sum[belong[i]][u[i]] ^= val[v[i]];
                sum[belong[i]][v[i]] ^= val[u[i]];
            }
            read(q);
            while(q--) {
                read(op); read(x); read(y);
                if(op == 1)
                    update(x, y);
                else {
                    long long a = s[x], b = s[y];
                    for(int i = 1; i <= num; ++i) if(lazy[i]) {
                        a ^= sum[i][x];
                        b ^= sum[i][y];
                    }
                    printf("%d", (int)(a == b));
                }
            }
            puts("");
        }
        return 0;
    }
    

    B. Crazy Binary String

    solved at 00:16

    签到

    D. Big Integer

    upsolved 队友做的

    F. Planting Trees

    upsolved

    (O(n^3))单调队列,我是傻逼

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 505;
    
    int d[N][N], n, m, T, ans, mx[N], mn[N];
    int minn[N], maxx[N];
    int h_mn, t_mn, h_mx, t_mx;
    
    int main() {
    	scanf("%d", &T);
    	while(T--) {
    		ans = 0;
    		scanf("%d%d", &n, &m);
    		for(int i = 1; i <= n; ++i) {
    			for(int j = 1; j <= n; ++j) 
    				scanf("%d", &d[i][j]);
    		}
    		for(int up = 1; up <= n; ++up) {
    			memset(mx, 0, sizeof(mx));
    			memset(mn, 0x3f, sizeof(mn));
    			for(int down = up; down <= n; ++down) {
    				h_mn = t_mn = h_mx = t_mx = 0;
    				for(int k = 1, left = 0; k <= n; ++k) {
    					mx[k] = max(mx[k], d[down][k]);
    					mn[k] = min(mn[k], d[down][k]);
    					for(; h_mn != t_mn && mn[minn[t_mn - 1]] > mn[k]; ) t_mn--;
    					minn[t_mn++] = k;
    					for(; h_mx != t_mx && mx[maxx[t_mx - 1]] < mx[k]; ) t_mx--;
    					maxx[t_mx++] = k;
    					for(; h_mn != t_mn && h_mx != t_mx && mx[maxx[h_mx]] - mn[minn[h_mn]] > m;) {
    						if(maxx[h_mx] < minn[h_mn])
    							left = maxx[h_mx++];
    						else
    							left = minn[h_mn++];
    					}
    					ans = max(ans, (down - up + 1) * (k - left));
    				}
    			}
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
    

    G. Removing stones

    upsolved

    等价于询问有多少个区间的区间最大值小于等于区间和

    题解说是找最大值然后枚举左右两边较短的那一边的端点然后二分查另一边的端点再分治,看了别人写了个暴力枚举不合法区间的然后跑的贼快,复杂度不太会算

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 3e5 + 10;
    
    int a[N], T, n;
    long long ans;
    
    int main() {
    	scanf("%d", &T);
    	while(T--) {
    		ans = 0;
    		scanf("%d", &n);
    		for(int i = 1; i <= n; ++i) 
    			scanf("%d", &a[i]);
    		for(int i = 1; i <= n; ++i) {
    			int l = i, r = i;
    			long long sum = 0;
    			while(l > 1 && sum + a[l - 1] < a[i]) l--, sum += a[l];
    			while(r < n && sum + a[r + 1] < a[i]) r++, sum += a[r];
    			ans += r - i + 1;
    			for(int j = l; j < i; ++j) {
    				sum -= a[j];
    				while(r < n && sum + a[r + 1] < a[i]) r++, sum += a[r];
    				ans += r - i + 1;
    			} 
    		}
    		printf("%lld
    ", 1LL * n * (n + 1) / 2- ans);
    	}
    	return 0;
    }
    

    H. Magic Line

    solved at 00:36

    要求用一条直线把平面上的点分成两部分,两部分个数相同且不能有点在线上

    注意到点的坐标范围只有(1000)而你最终输出的线的坐标可以到(1e9)

    一定可以用一条近似竖直线的线

    把点分开

    I. Median

    upsolved

    给定原序列的中位数序列(长度为(n-2)),构造一个原序列

    J. LRU management

    solved at 04:59(+22)

    队友做的,他手写了一个链表。。。

    用几个map维护就好了,利用map的迭代器可以自增或是自减的性质就好了

    那个string可以看成一个11进制数(区分前置零)

    我在贴上来的时候把快读删掉了,就是read那个函数的实现,用的是fread

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5e5 + 10;
    int T, q, m, op, v;
    long long ss;
    char s[12];
    map<int, long long> ptos;
    map<long long, int> stop, stov;
    
    long long convert(char s[]) {
    	long long val = 0;
    	for(int i = 0; s[i]; ++i) {
    		val = val * 11 + s[i] - '0' + 1;
    	}
    	return val;
    }
    
    int main() {
    	read(T);
    	while(T--) {
    		ptos.clear(); stop.clear(); stov.clear();
    		read(q); read(m);
    		ptos[100000] = 1e18;
    		stop[1000000000000000000LL] = 100000;
    		stov[1000000000000000000LL] = 100;
    		while(q--) {
    			read(op); read(s); read(v);
    			ss = convert(s);
    			if(op == 0) {
    				if(stov.count(ss)) {
    					printf("%d
    ", stov[ss]);
    					int fi = ptos.begin()->first;
    					int pos = stop[ss];
    					ptos.erase(ptos.find(pos));
    					stop[ss] = fi - 1;
    					ptos[fi - 1] = ss;
    				}
    				else {
    					stov[ss] = v;
    					int fi = ptos.begin()->first;
    					stop[ss] = fi - 1;
    					ptos[fi - 1] = ss;
    					if(ptos.size() > m) {
    						long long es = ptos.rbegin()->second;
    						ptos.erase(--ptos.end());
    						stop.erase(stop.find(es));
    						stov.erase(stov.find(es));
    					}
    					printf("%d
    ", v);
    				}
    			}
    			else {
    				if(!stov.count(ss)) {
    					puts("Invalid");
    					continue;
    				}
    				int pos = stop[ss];
    				if(v == 0) {
    					printf("%d
    ", stov[ss]);
    				}
    				else {
    					map<int, long long>::iterator it = ptos.find(pos);
    					if(v == 1) {
    						if(it == ptos.begin()) {
    							puts("Invalid");
    							continue;
    						}
    						it--;
    						if(stov[it->second] == 100) {
    							puts("Invalid");
    							continue;
    						}
    						printf("%d
    ", stov[it->second]);
    					}
    					else {
    						if(++it == ptos.end()) {
    							puts("Invalid");
    							continue;
    						}
    						if(stov[it->second] == 100) {
    							puts("Invalid");
    							continue;
    						}
    						printf("%d
    ", stov[it->second]);
    					}
    				}
    			}
    		}
    	}
    	return 0;
    }
    

    用map维护string(实际上是数)到list<int>::iterator的映射似乎写起来更简单

  • 相关阅读:
    ReentrantReadWriteLock源码探究
    ReentrantLock源码探究
    CyclicBarrier源码探究 (JDK 1.8)
    ThreadLocal源码探究 (JDK 1.8)
    CountDownLatch源码探究 (JDK 1.8)
    ConcurrentHashMap源码探究 (JDK 1.8)
    备忘录模式
    variable precision SWAR算法
    建造者模式
    Spring MVC 解决乱码
  • 原文地址:https://www.cnblogs.com/tusikalanse/p/11247289.html
Copyright © 2020-2023  润新知