首页 > 其他分享 >做题记录

做题记录

时间:2025-01-10 10:02:15浏览次数:1  
标签:cnt 记录 int arr mid xx dfn

CF600E

线段树合并典题。

P3899

可以发现 \(a\) 固定了所以可以分讨。

  • 当 \(a\) 在 \(b\) 下面时,可以发现 \(b\) 能取的个数是 \(\min(k,dep_a-1)\) 而 \(c\) 的个数就是 \(siz_a-1\) 然后乘起来就是总方案数。
  • 当 \(a\) 在 \(b\) 上面时,可以推出 \(dep_b-dep_a\leq k\) 并且 \(b\) 在 \(a\) 的子树中,而 \(c\) 的方案数就是 \(siz_b-1\) 那么只需要用主席树维护区间在 \(dfn_x\sim lst_x\) 之间的点且 \(dep_x\leq dep_a+k\) 的 \(siz_x-1\) 之和即可。

P7215

考虑连边,我们用 \(i\to j\) 表示如果 \(i\) 要合法那么一定要合并 \(j\) 城镇所以我们可以发现最后合法的一定是一个无出边的连通块,那么我们考虑如何连边首先我们发现可以将一种颜色的点按照 dfs 序排序然后两两之间的路径一定包含了所有能经过的,所以我们可以对于每对路径之间的点都会被此颜色连边而转移到 dfs 序上就是此颜色回向一段连续的区间连边,那么考虑线段树优化建图由于只有转到树剖上才能使 dfs 序连续所以考虑用树剖优化来建图,最后跑一边 tarjan 统计连通块中颜色小于等于 \(k\) 的点数最小且无出边的连通块即可。

P3703

考虑用线段树维护根节点到 \(x\) 的答案,然后我们考虑对于每次修改一定是将 \(1\sim x\) 的路径上的答案,对于修改 \(1\) 可以考虑树剖去修改 \(1\sim x\) 上的值,对于能影响到的点只需要记录一个颜色最上面的点和最下面的点然后每次暴力往上跳并用线段树修改即可,并且将 \(1\sim x\) 上的颜色全部染成 \(x\),对于修改 \(2\) 我们可以发现答案等于 \(dep_x+dep_y-2\times dep_{lca_{x,y}}+1\),对于修改 \(3\) 的答案就是 \(dfn_x\sim dfs_x+siz_x-1\) 这一段中答案的最大值。

#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define rep1(i,x,y) for(register int i=x;i>=y;--i)
#define int long long
#define fire signed
#define il inline
template<class T> il void print(T x) {
	if(x<0) printf("-"),x=-x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + '0');
}
template<class T> il void in(T &x) {
    x = 0; char ch = getchar();
    int f = 1;
    while (ch < '0' || ch > '9') {if(ch=='-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
    x *= f;
}
int T=1;
const int N=1e5+10;
int dfn[N],siz[N],son[N],dep[N];
int top[N],mp[N],f[N][20],n;
vector<int>v[N];
struct node{
	int l,r;
	int Max;
	int tag1;
}tr[N<<2];
struct Node{
	int l,r;
	int val,tag;
}tt[N<<2];
void build1(int u,int l,int r) {
	tt[u]={l,r};
	if(l==r) {
		tt[u].val=mp[l];
		return;
	}
	int mid=l+r>>1;
	build1(u<<1,l,mid);
	build1(u<<1|1,mid+1,r);
}
void down1(int u) {
	if(tt[u].tag) {
		tt[u<<1].tag=tt[u].tag;
		tt[u<<1|1].tag=tt[u].tag;
		tt[u<<1].val=tt[u].tag;
		tt[u<<1|1].val=tt[u].tag;
		tt[u].tag=0;
	}
}
void add(int u,int l,int r,int val) {
	if(tt[u].l>=l&&tt[u].r<=r) {
		tt[u].tag=tt[u].val=val;
		return;
	}
	down1(u);
	int mid=tt[u].l+tt[u].r>>1;
	if(mid>=l) add(u<<1,l,r,val);
	if(mid<r) add(u<<1|1,l,r,val);
}
int get_yan(int u,int x) {
	if(tt[u].l==tt[u].r) return tt[u].val;
	down1(u);
	int mid=tt[u].l+tt[u].r>>1;
	if(mid>=x) return get_yan(u<<1,x);
	return get_yan(u<<1|1,x);
}
void up(int x) {
	tr[x].Max=max(tr[x<<1].Max,tr[x<<1|1].Max);
}
void down(int x) {
	if(tr[x].tag1) {
		tr[x<<1].tag1+=tr[x].tag1;
		tr[x<<1|1].tag1+=tr[x].tag1;
		tr[x<<1].Max+=tr[x].tag1;
		tr[x<<1|1].Max+=tr[x].tag1;
		tr[x].tag1=0;
	}
}
void build(int u,int l,int r) {
	tr[u]={l,r};
	if(l==r) {
		tr[u].Max=dep[mp[l]];
		return;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	up(u);
}
void dfs(int x,int fa) {
	siz[x]=1;
	f[x][0]=fa;
	dep[x]=dep[fa]+1;
	for(auto to:v[x]) {
		if(to==fa) continue;
		dfs(to,x);
		siz[x]+=siz[to];
		if(siz[son[x]]<siz[to]) son[x]=to;
	}
}
int L[N],R[N];
void init() {
	rep(j,1,19) rep(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	rep1(i,19,0) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	rep1(i,19,0) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
int idx;
void modify1(int u,int l,int r,int k) {
	if(tr[u].l>=l&&tr[u].r<=r) {
		tr[u].tag1+=k;
		tr[u].Max+=k;
		return;
	}
	down(u);
	int mid=tr[u].l+tr[u].r>>1;
	if(mid>=l) modify1(u<<1,l,r,k);
	if(mid<r) modify1(u<<1|1,l,r,k);
	up(u);
}
void dfs1(int x,int head) {
	top[x]=head;
	dfn[x]=++idx;
	mp[idx]=x;
	if(!son[x]) return;
	dfs1(son[x],head);
	for(auto to:v[x]) if(!dfn[to]) dfs1(to,to);
}
int Ans(int u,int l,int r) {
	if(tr[u].l>=l&&tr[u].r<=r) {
		return tr[u].Max;
	}
	int mid=tr[u].l+tr[u].r>>1,res=0;
	down(u);
	if(mid>=l) res=Ans(u<<1,l,r);
	if(mid<r) res=max(res,Ans(u<<1|1,l,r));
	return res;
}
void gai(int x,int y,int k){
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		add(1,dfn[top[x]],dfn[x],k);
		x=f[top[x]][0];
	}
	if(dfn[x]>dfn[y]) swap(x,y);
	add(1,dfn[x],dfn[y],k);
}
int m;
int jump(int x,int t) {
	rep1(i,19,0) if(dep[f[x][i]]>dep[t]) x=f[x][i];
	return x;
}
void change(int x) {
	while(x) {
		int xx=get_yan(1,dfn[x]);
		int rr=R[xx];
		modify1(1,dfn[L[xx]],dfn[L[xx]]+siz[L[xx]]-1,-1);
		int ff=0;
		if(xx!=x) {
			int now=jump(xx,x);
			ff=now;
			modify1(1,dfn[now],dfn[now]+siz[now]-1,1);
		}
		x=f[L[xx]][0];
		if(ff!=0) L[xx]=ff;
	}
}
void solve() {
	in(n),in(m);
	rep(i,1,n-1) {
		int x,y;
		in(x),in(y);
		v[x].pb(y);
		v[y].pb(x);
	}
	rep(i,1,n) L[i]=R[i]=i;
	dfs(1,0);
	dfs1(1,1);
	build(1,1,n);
	build1(1,1,n);
	init();
	while(m--) {
		int opt;
		in(opt);
		if(opt==1) {
			int x;
			in(x);
			modify1(1,1,n,1);
			int xx=get_yan(1,dfn[x]);
			int ll=L[xx];
			modify1(1,dfn[ll],dfn[ll]+siz[ll]-1,-1);
			if(x!=xx) {
				int now=jump(xx,x);
				modify1(1,dfn[now],dfn[now]+siz[now]-1,1);
			}
			change(f[L[xx]][0]);
			gai(1,x,x);
			if(xx!=x) L[xx]=jump(xx,x);
			else L[xx]=0;
			L[x]=1,R[x]=x;
		}else if(opt==2){
			int x,y;
			in(x),in(y);
			int fa=lca(x,y);
			printf("%lld\n",Ans(1,dfn[x],dfn[x])+Ans(1,dfn[y],dfn[y])-2*Ans(1,dfn[fa],dfn[fa])+1);
		}else {
			int x;
			in(x);
			printf("%lld\n",Ans(1,dfn[x],dfn[x]+siz[x]-1));
		}
	}
}
fire main() {
	while(T--) {
		solve();
	}
	return false;
}

CF1418G

没脑子题,考虑分治,我们可以将左右能匹配的用哈希来让其匹配那么就成了左边一个桶然后枚举右边的判断是否能接上即可,这里我们可以对 \(j\) 第 \(i\) 次出现给他一个值然后让左边的 \(1\) 次的值能与右边地 \(2\) 次出现的值抑或为 \(0\) 但是我们发现对于左右同一个值都出现了 \(3\) 次的情况也会被计入答案那么我们对于每一个 \(i\sim mid\) 的后缀算出一个右端点能到的最大值 \(r\) 只需要在 \(mid+1\sim r\) 查询 \(x\) 的出现次数即可,直接主席树即可。

void get(int l,int r) {
	if(r-l+1<3) return;
	int mid=l+r>>1;
	get(l,mid);
	get(mid+1,r);
	idx=false;
	int s=0;
	rep(i,l,r) cnt[a[i]]=0;
	rt[mid]=false;
	cc=0;
	rep(i,l,r) {
		int aa=rnd64(),bb=rnd64(),cc=rnd64();
		mp[a[i]][1]=aa*cc;
		mp[a[i]][2]=bb;
		ma[a[i]][1]=bb;
		ma[a[i]][2]=aa*cc;
	}
	rep(i,l,r) {
		rt[i]=0;
		int aa=rnd64(),bb=rnd64(),cc=rnd64();
		mpp[a[i]][1]=aa*cc;
		mpp[a[i]][2]=bb;
		maa[a[i]][1]=bb;
		maa[a[i]][2]=aa*cc;
	}
	vector<int>v;
	int tot=0;
	int s1=0,Maxx=0;
	rep(i,mid+1,r) {
		cnt[a[i]]++;
		if(cnt[a[i]]>3) break;
		Maxx=i;
		s^=mp[a[i]][cnt[a[i]]];
		s^=mp[a[i]][cnt[a[i]]-1];
		s1^=mpp[a[i]][cnt[a[i]]];
		s1^=mpp[a[i]][cnt[a[i]]-1];
		val[i]={s,s1};
		arr[++cc]={s,s1};
	}
	s1=0;
	sort(arr+1,arr+1+cc);
	int mm=unique(arr+1,arr+1+cc)-arr-1;
	rep(i,l,r) cnt[a[i]]=0;
	rep(i,mid+1,r) {
		cnt[a[i]]++;
		if(cnt[a[i]]>3) break;
		rt[i]=rt[i-1];
		int id=lower_bound(arr+1,arr+1+mm,val[i])-arr;
		rt[i]=modify(rt[i],1,mm,id);
	}
	s=0;
	rep(i,l,r) cnt[a[i]]=0,head[a[i]]=0;
	s1=0;
	int Max=Maxx+1;
	rep1(i,mid,l) {
		cnt[a[i]]++;
		if(!head[a[i]]) head[a[i]]=i;
		if(cnt[a[i]]>3) break;
		Max=min(Max,nxt[head[a[i]]][4-cnt[a[i]]]);
		s^=ma[a[i]][cnt[a[i]]];
		s^=ma[a[i]][cnt[a[i]]-1];
		s1^=maa[a[i]][cnt[a[i]]];
		s1^=maa[a[i]][cnt[a[i]]-1];
		int id=lower_bound(arr+1,arr+1+mm,make_pair(s,s1))-arr;
		if(arr[id]!=make_pair(s,s1)) continue;
		res+=Ans(rt[Max-1],1,mm,id);
	}
}

下面是抄的,写的比较好。

    n = read();
    for (re int i = 1;i <= n;i++) tmp[i] = {rnd(),rnd()};
    for (re int i = 1;i <= n;i++){
        vis[arr[i] = read()]++;
        if (vis[arr[i]] % 3 == 1) val[i] = tmp[arr[i]].fst;
        else if (vis[arr[i]] % 3 == 2) val[i] = tmp[arr[i]].snd;
        else val[i] = tmp[arr[i]].fst ^ tmp[arr[i]].snd;
    }
    for (re int i = 1;i <= n;i++) val[i] ^= val[i - 1];
    fill(vis + 1,vis + n + 1,0); num[0]++;
    for (re int i = 1,j = 1;j <= n;j++){
        vis[arr[j]]++;
        while (vis[arr[j]] > 3){
            vis[arr[i]]--; num[val[i - 1]]--;
            i++;
        }
        ans += num[val[j]]++;
    } printf("%lld",ans);

CF489F

我们可以统计给定的 \(m\) 行中每一列有多少个 \(1\) 然后我们考虑对于每一列去 dp 我们定义 \(f_{i,j,k}\) 表示现在处理了前 \(i\) 列有 \(j\) 行上是 \(0\) 个 \(1\),有 \(k\) 行上有 \(1\) 个 \(1\) 然后随便转移一下即可。

CF1744F

因为 \(mex>med\) 所以 \(0\sim med\) 的值一定都是出现过的,那么我们考虑枚举中位数 \(x\) 然后求出 \(0\sim x\) 都出现的最小区间 \(l\sim r\) 然后我们发现当区间长度等于 \(2\times (x+1)\) 或 \(2\times (x+1)-1\) 才能满足条件所以考虑对于一个区间求从左右选一个后缀和前缀使其长度为 \(x\) 的答案即可,这个可以直接推柿子。

CF323C

因为这是两个排列所以可与第一个序列来建立主席树下标是它在第二个序列中出现的位置,然后主席树就做完了。

CF903D

发现如果全部都算 \(y-x\) 那么可以用一颗树状数组解决,而此答案对于正确答案就只多了 \(|y-x|=1\) 的所以考虑每次扫过去开桶记录然后每次把多加的减去即可。

CF1468A

发现对于一个数 \(x\) 它前面的两个数中至少有一个小于等于 \(x\) 所以考虑定义状态 \(f_i\) 表示到 \(i\) 能选的最多的点,转移为 \(f_i=f_j+cnt_{j,i}\) 其中 \(a_i\geq a_j,j<i\) 且 \(cnt_{i,j}\) 表示 \(i+1\sim j-1\) 中是否有数 \(\geq a_j\),有则为 \(1\) 否则为 \(0\)。这是 \(n^2\) 的考虑优化,发现对于每个点可以求出其前面最靠近他的一个 \(\geq a_i\) 的点,当 \(j\leq lst_i\) 时将 \(f_i\) 加一否则不加,所以考虑主席树,我们只需要在 \(lst_i\) 的主席树上找 \(a_j\leq a_i\) 的最大的 \(f_j+1\) 即可,后面的一坨就是第 \(i-1\) 棵树上的最大值。

标签:cnt,记录,int,arr,mid,xx,dfn
From: https://www.cnblogs.com/highkj/p/18656716

相关文章

  • markdown学习记录
    markdown学习标题标题用“#”字体这是加粗(两个星号)这是倾斜(一个星号)加粗+倾斜(三个星号)这是删除线(两个~~)引用大于号是引用分割线(“---”或“***”)插入图片!+[名称]+(URL)超链接[地址名]+(网址)我的博客地址列表有序用数字,无序用“-”号ABCEFG表格......
  • [CF2057F] Formation 做题记录
    link对我比较有意义的一道题目。我们先逐步分析,对于单个询问,先钦定最大值位置\(i\),我们现在的目标是最大化\(a_i\)的值。这显然有单调性,考虑二分一个\(mid\)表示最终值,那么会出现一个\(l(l\lei)\)以及一个序列\(c_{0\dotsl-1}\)有\(c_i=\lceil\dfrac{mid}{2......
  • linux网桥(Linux Bridge)的一些个人记录
    目录1.LinuxBridge简述2.网桥创建创建配置持久化在Debian/Ubuntu系统上:在CentOS/RHEL系统上:启用和验证3.关于linux网桥不转发ip帧的问题原因解决配置持久化4.查看网桥学习交换表手动添加或删除条目添加条目删除条目配置静态条目设置条目的老化时间持久化配置5.关于linux网桥......
  • 记录---JS 的蝴蝶效应 —— 事件流
    ......
  • linux8安装oracle 11g遇到的问题记录
    大家都知道oracle11g在linux6或7上安装是没有问题的,但在linux8上安装时在link编译环节会遇见各种问题。按照oracle官网的说法,可直接跳过这些错误,等他安装完毕,然后打补丁,再重新编译即可。官网给出的方案1、InstallOracleDatabase11.2.0.4(softwareonly):Note:Ignoreany......
  • 一次web服务失去响应记录
    现象:线上服务无法对接口进行响应,接口全部超时,但是Java进程还是在运行中,jvmGC日志正常。jstack命令查看线程情况: 大量线程处于BLOCKED状态,等待锁0x00000000cbc9b9c8的释放;该锁被持有的线程:scheduling-1,是一个异步线程。 通过观察上图,发现锁在getAccessToken方法中被获取,该......
  • 2024.12 做题记录
    [CF2042D]Recommendations\(\text{Link}\)发现所求即为包含\([l,r]\)的所有区间的交的长度减去\([l,r]\)的长度。考虑所有包含\([l,r]\)的区间\([L,R]\),不难发现其满足\(L\lel,r\leR\)。由于我们要求交,所以求出满足该条件的\(L\)的最大值和\(R\)的最小值即可。扫......
  • 1.9 CW 模拟赛 赛时记录
    前言策略不变,继续搞看题\(4\)神秘,开骗\(\rm{T1}\)思路先考虑对于一个确定的\(a\)怎么做发现一个数能否被删除与删除的顺序无关,本质上是因为\(j,l\)并不因为操作而改变考虑到一个数能被删除,仅当其在前后缀中都不为最大值,也就是说可以\(\mathcal{O}(n)\)......
  • 2025 1.9 做题记录
    CF1787D这里有个很典的trick。我们将\(i+a_i\)向\(i\)连边,那么只要一个\(<0\)或\(>n\)的点能够走到\(i\),就说明\(i\)能在有限的次数内出去。这玩意跑个拓扑排序即可。那么现在我们可以考虑从\(1\)开始走,因为只能修改一个点的值,记\(u\)为\(1\)走若干步后到达的......
  • 学习记录:C++ 中 const 引用的使用及其好处
    在C++编程中,const引用是一种非常重要且常见的参数传递方式。无论是在类的构造函数、成员函数,还是全局函数中,使用const引用作为函数参数都能带来显著的性能和安全性优势。今天,我们将分享const引用在函数参数中的一些常见用法及其带来的好处。1.避免不必要的拷贝在C++......