zoukankan      html  css  js  c++  java
  • 20210716模拟赛

    是 zzq 神仙出的题。

    而且看到了 zzq 神仙本人啦!

    T1

    奇妙的构造,有些眼熟但应该没见过。那一道是环上交换前缀和的毒瘤题,不会。

    这个一开始想分成若干段,长度为 20 ,然后每一段分别使用最优解法,发现答案并不是很优,只有 30pts 的样子。

    考虑如果这段的开头是 0 ,那么把整段后移,不会更劣,似乎确实优了一点点,大概能有个 30 多分。

    想把 20 变成更大一点的数,在时间复杂度允许的情况下大概是不到 40 分。

    然后乱搞,对于每一个 1 ,向后枚举 100 个位置,看是否出现了符合要求的三个 1 ,然后把它们一起删掉。

    发现优化的非常明显,可以直接分数拿满。

    zzq说我们吊打了 IOI AKer和国家队(

    正解就是找当前这个 1 有没有办法给他和另外两个一起删掉,否则使用奇怪的方法把它删掉。

    T2

    神仙题,仅对于我来说,毕竟我菜。

    首先想到一定是树形结构,组成了一个森林,如果使用 LCT 没准不错可惜我不会 LCT。朴素想法使用 (O(n^3)) 暴力,可惜没有分。思考平方做法,或者带log。我们每次将一个点改变父亲的时候,把它的儿子的 fa 倍增数组给重构出来,可以在 (O(n^2logn)) 的时间复杂度内修改,在 (O(n^2logn)) 的复杂度内查询。然后发现我干嘛构建倍增数组,直接维护根就完了。时间复杂度 (O(n^2))

    考虑如何解决随机数据。可以发现修改的时间消耗大概不会很多,期望应该是 (O(logn)) 重构一次。看怎么处理询问。给每个点维护出应该的颜色,然后使用分块维护一下,可以 (sqrt{n}) 进行询问。

    正解也有分块。离线做法,将询问分块,发现每块内父亲改变的点只有 (sqrt{n}) 个,维护这些点,修改的时候暴力重构即可,复杂度是单次 (O(sqrt{n})) 。考虑询问。我们认为这些特殊点有各自的颜色,这个可以维护。找被一个特殊点统帅的点有哪些,对于一个特殊点,分块维护每一块里的被统帅点个数,然后前缀和预处理一下。查询的时候对于整块,枚举特殊点查询,对于散点,查看他的被哪个特殊点统帅,计入贡献。对于那些不被统帅的非特殊点。随便用个数据结构比如说树状数组维护一下就好了。最终复杂度可以 (O(nsqrt{n}))

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    
    using namespace std;
    
    int read()
    {
    	int a = 0,x = 1;char ch = getchar();
    	while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();}
    	while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();}
    	return a*x;
    }
    const int N=2e5+7;
    int n,fa[N],a[N],q,b,head[N],go[N],nxt[N],cnt,anc[N];
    struct node{int op,x,y;}arr[N];
    void add(int u,int v)
    {
    	go[++cnt] = v;
    	nxt[cnt] = head[u];
    	head[u] = cnt;
    }
    int _fa[N],_head[N],_go[N],_nxt[N],_cnt,_a[N],s[N][400],vis[N],col[N];
    vector<int>g;
    void _add(int u,int v)
    {
    	_go[++_cnt] = v;
    	_nxt[_cnt] = _head[u];
    	_head[u] = _cnt;
    }
    void dfs(int u,int h)
    {
    	int ret = 1;
    	for(int e = head[u];e;e = nxt[e]) {
    		int v = go[e];a[v] = a[u];
    		dfs(v,vis[u] ? u : h);
    	}
    	_fa[u] = h;if(vis[u]) h = u,ret = 0,_a[u] = a[u],g.push_back(u);anc[u] = h;
    	if(anc[u] == u && _fa[u]) _add(_fa[u],u);
    	s[h][col[u]] ++;
    }
    
    void update(int u)
    {
    	for(int e = _head[u];e;e = _nxt[e]) {
    		int v = _go[e];if(_fa[v] != u || _a[v] == _a[u]) continue;
    		_a[v] = _a[u];update(v);
    	}
    }
    int S[N];
    void Add(int p,int x)
    {
    	for(int i = p;i <= n;i += i&-i) S[i] += x;
    }
    int query(int p) 
    {
    	int ret = 0;
    	for(int i = p;i >= 1;i -= i&-i) ret += S[i];
    	return ret;
    } 
    int query(int l,int r)
    {
    	int ret = 0;
    	if(col[r] > col[l]) for(auto o : g) {
    		ret += (s[o][col[r]-1] - s[o][col[l]])*_a[o];
    	}
    	for(int i = l;i <= r && col[l] == col[i];i ++) {
    		ret += anc[i] ? _a[anc[i]] : 0;
    	}
    	if(col[l] != col[r]) for(int i = r;i >= l && col[i] == col[r];i --) {
    		ret += _a[anc[i]];
    	}
    	return ret + query(r) - query(l-1);
    }
    void solve(int l,int r)
    {
    	for(int i = l;i <= r;i ++) {
    		if(arr[i].op <= 2) vis[arr[i].x] = 1;
    	}
    	for(int i = 1;i <= n;i ++) head[i] = _head[i] = S[i] = 0;_cnt = cnt = 0;
    	for(int i = 1;i <= n;i ++) {
    		if(fa[i] != i) add(fa[i],i);
    	}g.clear();
    	for(int i = 1;i <= n;i ++) {
    		if(fa[i] == i) {dfs(i,0);}
    	}
    	for(auto o : g) {
    		for(int i = 1;i <= col[n];i ++) s[o][i] += s[o][i-1];
    	}
    	for(int i = 1;i <= n;i ++) {
    		if(anc[i] == 0) Add(i,a[i]);
    	}
    	for(int i = l;i <= r;i ++) {
    		if(arr[i].op == 1) {
    			_fa[arr[i].x] = arr[i].x;_a[arr[i].x] = arr[i].y;
    			update(arr[i].x);
    		} else if(arr[i].op == 2) {
    			_fa[arr[i].x] = anc[arr[i].y],_a[arr[i].x] = anc[arr[i].y] ? _a[anc[arr[i].y]] : a[arr[i].y];
    			if(_fa[arr[i].x]) _add(_fa[arr[i].x],arr[i].x);
    			update(arr[i].x);
    		} else {
    			printf("%d
    ",query(arr[i].x,arr[i].y)); 
    		} 
    	}
    	for(auto o : g) {
    		for(int i = 1;i <= col[n];i ++) s[o][i] = 0;
    	}
    	for(int i = l;i <= r;i ++) {
    		if(arr[i].op <= 2) vis[arr[i].x] = 0;
    	}
    }
    
    int main()
    {
    	freopen("cells.in","r",stdin);freopen("cells.out","w",stdout);
    	n = read(),q = read();b = n;
    	for(int i = 1;i <= n;i ++) a[i] = read(),fa[i] = i,col[i] = (i-1)/b+1;
    	for(int i = 1;i <= q;i ++) {
    		arr[i].op = read(),arr[i].x = read(),arr[i].y = read();
    	}
    	for(int i = 1;i <= q;i ++) {
    		if(i%b == 1) solve(i,min(q,i+b-1));
    		if(arr[i].op == 1) a[arr[i].x] = arr[i].y,fa[arr[i].x] = arr[i].x;
    		else if(arr[i].op == 2) fa[arr[i].x] = arr[i].y;
    	}
    } 
    

    T3

    神仙构造,并不会做。

    对于 (m = 1) 的时候,只有 (n = 1) 时有解。

    对于每一个铜丝全都小于等于 2 的,把长度为 2 的贴边放剩下的空位填 1 就好了。

    不小于 2 的,把所有大于 2 的左端弯折一下,然后剩下的空位用 2 补齐。长度为 n 的铜丝需要 n-3 个 2。

    忘记输出 yes 少了 40pts 的痛……

  • 相关阅读:
    无root权限安装tmux
    mosquitto_pub和mosquitto_sub 命令参数说明
    安装Mosquitto学习MOTT协议
    Linux之prink原理
    JZ2440支持设备树(1)-添加设备树之后kernel的启动参数跟dts里面不一致
    Linux可以生产uImage
    Ubuntu18.04下make menuconfig缺少ncurses库
    如何打开kernel最开始的打印
    buildroot管理uboot+kernel+rootfs
    STM32L071CBTX操作ECC508
  • 原文地址:https://www.cnblogs.com/nao-nao/p/15021794.html
Copyright © 2011-2022 走看看