pyyzDay13
杂题选讲
T1 数颜色
vector存颜色
二分查找
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
if(b==0) return 1;
if(b==1) return a%p;
int c=ksm(a,b/2,p);
c=c*c%p;
if(b%2==1) c=c*a%p;
return c%p;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
vector<int> col[300005];
int ccc[300005];
signed main()
{
//freopen("filename.in", "r", stdin);
//freopen("filename.out", "w", stdout);
int n=read(),m=read();
for(int i=1;i<=n;i++){
ccc[i]=read();
col[ccc[i]].push_back(i);
}
while(m--){
int opt=read();
if(opt==1){
int l=read(),r=read(),c=read();
int pl=lower_bound(col[c].begin(),col[c].end(),l)-col[c].begin()-1;
int pr=upper_bound(col[c].begin(),col[c].end(),r)-col[c].begin()-1;
if(pr-pl<=0) cout<<0<<'\n';
else cout<<pr-pl<<'\n';
}
else{
int x=read();
int co1=ccc[x];
int co2=ccc[x+1];
if(co1==co2) continue;
int pp=lower_bound(col[co1].begin(),col[co1].end(),x)-col[co1].begin();
col[co1][pp]=x+1;
pp=lower_bound(col[co2].begin(),col[co2].end(),x+1)-col[co2].begin();
col[co2][pp]=x;
swap(ccc[x],ccc[x+1]);
}
}
return 0;
}
T2 [JXOI2017] 加法
二分答案
区间左端点排序
每次选包含i的区间的右端点最大的
堆维护
树状数组维护差分
T3 [USACO20JAN] Cave Paintings P
dp+并查集维护连通块
T4 [ARC016D] 軍艦ゲーム
期望DP
发现母港形成环
二分答案破环成链
得到真答案与二分答案比较
trick:在DP中遇到环,且环的原因是某个值,可以直接二分这个值,得到真答案作比较
T5 koishi的数学题
数论分块
也可递推
调和级数求因数和
线性做法考虑线性求因数和
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
if(b==0) return 1;
if(b==1) return a%p;
int c=ksm(a,b/2,p);
c=c*c%p;
if(b%2==1) c=c*a%p;
return c%p;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int yin[1000005];
signed main()
{
//freopen("filename.in", "r", stdin);
//freopen("filename.out", "w", stdout);
int n=read();
for(int d=1;d<=n;d++){
for(int j=d;j<=n;j+=d){
yin[j]+=d;
}
}
int ans=n-1;
cout<<ans<<' ';
for(int i=2;i<=n;i++){
ans+=n-yin[i];
cout<<ans<<' ';
}
cout<<'\n';
return 0;
}
T6 Jamie and Tree
换根+树链剖分+分讨+线段树
考虑求LCA
T7 XOR Tree
一条路径异或和为0
等价于du ^ dv ^ a_lca(u,v)=0
du表示u~rt的路径
开set维护查找即可
树上启发式合并可降复杂度至nlogn
即先合并轻儿子
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
if(b==0) return 1;
if(b==1) return a%p;
int c=ksm(a,b/2,p);
c=c*c%p;
if(b%2==1) c=c*a%p;
return c%p;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int n;
int a[200005];
vector<int> tu[200005];
int ans,d[200005];
set<int> val[200005];
void dfs(int u,int fa){
d[u]=d[fa]^a[u];
val[u].insert(d[u]);
bool fl=0;
for(auto ed:tu[u]){
if(ed==fa) continue;
dfs(ed,u);
if(val[u].size()<val[ed].size()) swap(val[u],val[ed]);
for(auto v:val[ed]){
if(val[u].find(v^a[u])!=val[u].end()){
fl=1;
}
}
for(auto v:val[ed]) val[u].insert(v);
}
if(fl){
ans++;
val[u].clear();
}
}
signed main()
{
//freopen("filename.in", "r", stdin);
//freopen("filename.out", "w", stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
tu[u].push_back(v);
tu[v].push_back(u);
}
dfs(1,0);
cout<<ans<<'\n';
return 0;
}
T8 Nikita and game
找到一个连续段
维护其左侧和右侧的树的直径的端点
对加入的节点
去计算到l,r的距离
判断能否成为直径即可
T9 New Year Tree
发现每次加点最多贡献1
维护直径端点
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
#define jiaa(a,b) {a+=b;if(a>=MOD) a-=MOD;}
#define jian(a,b) {a-=b;if(a<0) a+=MOD;}
using namespace std;
int ksm(int a,int b,int p){
if(b==0) return 1;
if(b==1) return a%p;
int c=ksm(a,b/2,p);
c=c*c%p;
if(b%2==1) c=c*a%p;
return c%p;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
vector<int> tu[1000010];
int dep[1000010],f[1000010][25];
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
for(int i=0;i<=20;i++){
f[x][i+1]=f[f[x][i]][i];
}
for(auto ed:tu[x]){
if(ed==fa) continue;
f[ed][0]=x;
dfs(ed,x);
}
}
int lca(int x,int y){
if(dep[x]>dep[y]) swap(x,y);
for(int i=20;i>=0;i--){
if(dep[f[y][i]]>=dep[x]) y=f[y][i];
}
if(x==y) return x;
for(int i=20;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
}
return f[y][0];
}
signed main()
{
//freopen("filename.in", "r", stdin);
//freopen("filename.out", "w", stdout);
tu[1].push_back(2);
tu[1].push_back(3);
tu[1].push_back(4);
tu[2].push_back(1);
tu[3].push_back(1);
tu[4].push_back(1);
dfs(1,0);
int cnt=4;
int maxx=2;
int l=2,r=3;
int q=read();
while(q--){
int u=read();
tu[u].push_back(++cnt);
tu[cnt].push_back(u);
tu[u].push_back(++cnt);
tu[cnt].push_back(u);
dfs(u,f[u][0]);
int an1=dep[l]+dep[cnt]-dep[lca(l,cnt)]*2;
int an2=dep[r]+dep[cnt]-dep[lca(r,cnt)]*2;
if(an1>maxx||an2>maxx){
if(an1>maxx) r=cnt;
else l=cnt;
maxx=max(an1,an2);
}
cout<<maxx<<'\n';
}
return 0;
}
T10 [NordicOI 2025] 垃圾收集 / Garbage Collection
扫描线+线段树
T11 [NOISG 2020 Finals] Progression
可直接维护
难写!!!
不如差分
做完了
T12 Legacy
线段树优化建图
开两棵线段树:出树/入树
一棵外向树,一棵内向树
两颗线段树所有叶节点连0的边
互相可达
现考虑区间连区间
每次建新的中转点

浙公网安备 33010602011771号