模板集合

>w<

Windows 对拍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@echo off

set paht=C:\Windows\System32

:loop

data.exe
ddd.exe
pai.exe

fc ddd.out pai.out

if not errorlevel 1 goto loop

pause

goto loop

gvim 配置

1
2
3
4
5
6
7
8
9
10
set ts=4
set sw=4
set smarttab
set number
color desert
syntax on
set cindent
set guifont=Consolas:h16

imap ee <Esc>:w<CR>

一行 gcd

1
LL gcd(LL x,LL y){  return (y ? gcd(y,x%y) : x);}

线性基(带求交)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
struct bss{
int b[32];
bss(){
for(int i=0;i<=31;++i) b[i]=0;
}
bss(int x[]){
for(int i=0;i<=31;++i) b[i]=x[i];
}
void ist(int x){
for(int i=31;i>=0;--i)if(x>>i&1){
if(!b[i]){
b[i]=x;
return ;
}
x^=b[i];
}
}
bool chck(int x){
for(int i=31;i>=0;--i)if(x>>i&1)
x^=b[i];
return !x;
}
};
bss mg(bss x,bss y){
bss bwl=x,nb=x,z;
for(int i=0;i<=31;++i)if(y.b[i]){
int tma=0,tmb=y.b[i];
for(int j=i;j>=0;--j)if(tmb>>j&1){
if(bwl.b[j]){
tmb^=bwl.b[j],tma^=nb.b[j];
if(!tmb){
z.b[i]=tma;
break;
}
}
else{
bwl.b[j]=tmb;
nb.b[j]=tma;
break;
}
}
}
return z;
}

(小根)堆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int hp[110000],sz=0;
void ist(int z){
int x; hp[x=(++sz)]=z;
while(x!=1 && hp[x]<hp[x>>1]) swap(hp[x],hp[x>>1]),x>>=1;
}
void pp(){
hp[1]=hp[sz--];
int x=1,mnid=1;
for(;;){
mnid=x;
if((x<<1)<=sz && hp[x<<1]<hp[mnid]) mnid=(x<<1);
if((x<<1|1)<=sz && hp[x<<1|1]<hp[mnid]) mnid=(x<<1|1);
if(mnid==x) break;
swap(hp[mnid],hp[x]);
x=mnid;
}
}

后缀数组(下标从 1 开始)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
char s[1100000];  int n=0;
int rk[1100000],hght[1100000];
int cnt[220],cntrk[1100000];
int rk1[1100000],rk2[1100000];
int sa[1100000],tmpsa[1100000];
void gtsffxrk(){
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;++i) ++cnt[(int)s[i]];
for(int i=1;i<=210;++i) cnt[i]+=cnt[i-1];
for(int i=1;i<=n;++i) rk[i]=cnt[(int)s[i]];
for(int l=1;l<n;l<<=1){
for(int i=1;i<=n;++i) rk1[i]=rk[i],rk2[i]=(i+l>n ? 0 : rk[i+l]);
fill(cntrk+1,cntrk+1+n,0);
//每一步都必须fill,因为cntrk求了前缀和,cntrk--并不会把所有cntrk都减成0
for(int i=1;i<=n;++i) ++cntrk[rk2[i]];
for(int i=1;i<=n;++i) cntrk[i]+=cntrk[i-1];
//i从1开始,注意因为空字符的存在所以还是有0rank的
for(int i=n;i>=1;--i) tmpsa[cntrk[rk2[i]]--]=i;
fill(cntrk+1,cntrk+1+n,0);
for(int i=1;i<=n;++i) ++cntrk[rk1[i]];
for(int i=1;i<=n;++i) cntrk[i]+=cntrk[i-1];
for(int i=n;i>=1;--i) sa[cntrk[rk1[tmpsa[i]]]--]=tmpsa[i];
rk[sa[1]]=1;
//如果rank从0开始,对于全部一样的串如"aaaa"会出问题,把最小的rank和空字符混淆
bool flg=true;
for(int i=2;i<=n;++i){
rk[sa[i]]=rk[sa[i-1]];
rk[sa[i]]+=(rk1[sa[i]]!=rk1[sa[i-1]] || rk2[sa[i]]!=rk2[sa[i-1]]);
if(rk1[sa[i]]==rk1[sa[i]] || rk2[sa[i]]==rk2[sa[i]]) flg=false;
//if(rk[sa[i]]==rk[sa[i-1]]) flg=false;
}
if(flg) break;
}
}
void gthght(){
int l=0;
for(int i=1;i<=n;++i)if(rk[i]>1){
int j=sa[rk[i]-1];
while(i+l<=n && j+l<=n && s[i+l]==s[j+l]) ++l;
//i+l表示的实际上是长度为i+l-1的串的最后一个字符
hght[rk[i]]=l;
l-=(l>0);
}
}

dinic(当前弧优化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const LL oo=1000000000000007;
struct edg{int y,nxt; LL v;}e[11000]; int lk[110],ltp=1;
//注意两倍边数组
void ist(int x,int y,int z){
e[++ltp]=(edg){y,lk[x],z}; lk[x]=ltp;
//注意结构体内变量顺序
e[++ltp]=(edg){x,lk[y],0}; lk[y]=ltp;
//因为要用i^1表示反向边所以边的标号从2开始
}
int n,m; int s,t;
int lvl[110];
int q[110],hd=0;
int crt[110];
bool gtlvl(){
memset(lvl,0,sizeof(lvl));
lvl[q[hd=1]=s]=1;
for(int k=1;k<=hd;++k){
crt[q[k]]=lk[q[k]];
//注意crt要初始化
for(int i=lk[q[k]];i;i=e[i].nxt)if(e[i].v && !lvl[e[i].y]){
q[++hd]=e[i].y;
lvl[e[i].y]=lvl[q[k]]+1;
}
}
return lvl[t];
}
LL mxflw(int x,LL y){
if(x==t) return y;
LL bwl=0,flw=0;
for(int i=crt[x];i && bwl<y;i=e[i].nxt)if(lvl[e[i].y]==lvl[x]+1 && e[i].v)
//注意i=crt[x]
if((flw=mxflw(e[i].y,min(y-bwl,e[i].v)))){
//注意y和v,易错点
e[i].v-=flw,e[i^1].v+=flw;
bwl+=flw;
if(!e[i].v) crt[x]=e[i].nxt;
//唯一的改动,很好写
//注意必须某条边跑满才能换下一个,否则会负优化
}
if(!bwl) lvl[x]=0;
return bwl;
}
LL dnc(){
LL bwl=0,flw=0;
while(gtlvl())while((flw=mxflw(s,oo))) bwl+=flw;
return bwl;
}

平衡树 treap(假删除)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
int c[110000][2],v[110000],u[110000],sz[110000],ntp=0,rt=0;
int nb[110000],fth[110000];
void rtt(int x,bool mk){
int l=mk^1,r=mk,y=fth[x],z=fth[fth[x]];
//l和r的选取必须看以左旋还是右旋为例
if(c[x][r]) fth[c[x][r]]=y;
//c[x][r]可能为空
fth[y]=x,fth[x]=z;
c[y][l]=c[x][r],c[x][r]=y;
//x肯定有爸爸,没有爸爸旋个毛线
if(z) c[z][c[z][1]==y]=x; //注意这里不是l和r
//总共涉及到3条边,所以共有6个赋值
sz[x]=sz[y],sz[y]=sz[c[y][0]]+sz[c[y][1]]+nb[y];
if(y==rt) rt=x;
//注意rt
}
void mt(int x){
while(fth[x] && u[x]<u[fth[x]]) rtt(x,c[fth[x]][0]==x);
}
void ist(int x,int y,int z){
if(!x){
x=++ntp;
if(!rt) rt=x;
v[x]=z,u[x]=rand();
sz[x]=1,nb[x]=1;
fth[x]=y; if(y) c[y][z>v[y]]=x;
//x肯定要设置爸爸,但爸爸可能为空,细节要考虑到
c[x][0]=0,c[x][1]=0;
mt(x);
return ;
}
++sz[x];
if(z==v[x]) ++nb[x];
else ist(c[x][z>v[x]],x,z);
}
void dlt(int x,int z){
if(!x) return ;
--sz[x];
if(z==v[x]) --nb[x];
else dlt(c[x][z>v[x]],z);
return ;
}
int gtrk(int x,int z){
if(!x) return -1;
if(z==v[x]) return sz[c[x][0]]+1;
else return gtrk(c[x][z>v[x]],z)+(z>v[x] ? sz[c[x][0]]+nb[x] : 0);
}
int slct(int x,int z){
if(!x) return -1;
if(z<=sz[c[x][0]]) return slct(c[x][0],z);
//注意别写混成gtrk
else if(z-sz[c[x][0]]<=nb[x]) return v[x];
else return slct(c[x][1],z-sz[c[x][0]]-nb[x]);
}
int gtcsctv(int x,int z,bool mk){
int l=mk,r=mk^1;
//前驱后继也是镜像操作
while(v[x]!=z){
if(!c[x][z>v[x]]){
ist(rt,0,z),dlt(rt,z);
//注意一定要从rt开始插入和删除,如果从x开始会有很多问题
//比如被旋走,比如插入途径加的sz没有删干净
x=ntp;
}
//保证第一遍查找的时候不会找到假节点
else x=c[x][z>v[x]];
//注意一定要else,否则新插入的点可能会被maintain跑
}
if(!c[x][l]){
while(fth[x] && c[fth[x]][r]!=x) x=fth[x];
if(!fth[x]) return -1;
x=fth[x];
}
else{
//注意这里是else,如果开始爸爸就不用再找儿子了
x=c[x][l];
while(c[x][r]) x=c[x][r];
}
if(nb[x]) return v[x];
else return gtcsctv(x,v[x],mk);
//如果偷懒不删除则要注意找到的点是否已经没有数了
//感觉这样容易反复查找被卡,但是没有证据
}

cdq 分治(三维数星星小于等于版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void cdq(int l,int r,int cl,int cr){
if(l>=r) return ;
if(cl==cr){
for(int i=l;i<=r;++i){
int tmp=1;
//注意这里对于全等点的处理
while(i+tmp<=r && a[i+tmp].a==a[i].a && a[i+tmp].c==a[i].c) ++tmp;
//i+tmp表示的实际上是长度为tmp+1的区间的右端点
for(int j=0;j<tmp;++j) a[i+j].ans+=tmp-1+qry(a[i].c);
//别忘了qry
mdf(a[i].c,tmp);
i+=tmp-1;
//注意是+tmp-1不是=也不是+tmp
}
for(int i=l;i<=r;++i) mdf(a[i].c,-1);
return ;
}
int md=(cl+cr)>>1;
int cnt1=0,cnt2=0;
for(int i=l;i<=r;++i){
if(a[i].b<=md){
mdf(a[i].c,1);
++cnt1;
}
else{
a[i].ans+=qry(a[i].c);
++cnt2;
}
}
for(int i=l;i<=r;++i)if(a[i].b<=md) mdf(a[i].c,-1);
cnt1+=l; cnt2+=cnt1;
for(int i=r;i>=l;--i) q[--(a[i].b<=md ? cnt1 : cnt2)]=a[i];
for(int i=l;i<=r;++i) a[i]=q[i];
cdq(l,cnt2-1,cl,md),cdq(cnt2,r,md+1,cr);
}
bool cmp(nds x,nds y){ return (x.a==y.a ? (x.b==y.b ? x.c<y.c : x.b<y.b) : x.a<y.a);}
//这个顺序很重要

树状数组

1
2
3
4
5
6
7
8
9
inline int lbt(int x){  return x&-x;}
//v[x]统计的是[x-lowbit(x)+1,x]的所有数
void mdf(int x,int z){ while(x<=m){ v[x]+=z; x+=lbt(x);}}
//+lowbit的目的不是把1变成0,而是把0变成1
int qry(int x){
int bwl=0;
while(x){ bwl+=v[x]; x-=lbt(x);}
return bwl;
}

tarjan 求割点(无向图)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int rd(){int z=0,mk=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')mk=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();}
return z*mk;
}
struct edg{int y,nxt;}e[210000]; int lk[21000],ltp=0;
void ist(int x,int y){
e[++ltp]=(edg){y,lk[x]}; lk[x]=ltp;
e[++ltp]=(edg){x,lk[y]}; lk[y]=ltp;
}
int n,m;
int dfn[21000],low[21000],dft=0;
int aq[21000],atp=0;
void tj(int x,int y){
dfn[x]=++dft; low[x]=dfn[x];
bool flg1=false,flg2=false;
for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y){
if(!dfn[e[i].y]){
tj(e[i].y,x);
if(!y && flg1) flg2=true;
//注意顺序!放到后边就错了
if(low[e[i].y]>=dfn[x]) flg1=true;
low[x]=min(low[x],low[e[i].y]);
}
else low[x]=min(low[x],dfn[e[i].y]);
//注意这里是dfn
}
if(y && flg1) aq[++atp]=x;
if(!y && flg2) aq[++atp]=x;
}
void prvs(){
for(int i=1;i<=n;++i) dfn[i]=0,low[i]=0;
dft=0;
atp=0;
}
int main(){
//freopen("ddd.in","r",stdin);
cin>>n>>m; prvs();
int l,r;
while(m --> 0){ l=rd(),r=rd(); ist(l,r);}
for(int i=1;i<=n;++i)if(!dfn[i]) tj(i,0);
sort(aq+1,aq+atp+1);
printf("%d\n",atp);
for(int i=1;i<=atp;++i) printf("%d ",aq[i]);
printf("\n");
return 0;
}

手写堆排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nds a[110000];
bool cmp(nds &x,nds &y){ return x.c<y.c;}
void st(){
for(int i=1;i<=m;++i)
for(int j=i;j>1 && b[j].c<b[j>>1].c;j>>=1) swap(b[j],b[j>>1]);
int sz=m;
for(int i=1;i<=m;++i){
a[i]=b[1];
swap(b[1],b[sz--]);
for(int j=1;j<=sz;){
int k=j;
if((j<<1)<=sz && b[j<<1].c<b[k].c) k=(j<<1);
if((j<<1|1)<=sz && b[j<<1|1].c<b[k].c) k=(j<<1|1);
if(k==j) break;
swap(b[j],b[k]);
j=k;
}
}
for(int i=1;i<=m;++i) b[i]=a[i];
}

费用流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const int oo=1000000007;
struct edg{int nxt,y,v,u;}e[31000]; int lk[4100],ltp=1;
void ist(int x,int y,int z,int w){
e[++ltp]=(edg){lk[x],y,z,w}; lk[x]=ltp;
e[++ltp]=(edg){lk[y],x,0,-w}; lk[y]=ltp;
}
int n,m,ft,st,fc,sc,a[2100];
int s,t;
int dstc[4100];
int q[41000],hd=0; bool vstd[4100];
int lst[4100],lse[4100];
bool spfa(){
for(int i=1;i<=t;++i){
vstd[i]=false;
dstc[i]=oo;
}
dstc[q[hd=1]=s]=0;
for(int k=1;k<=hd;++k){
for(int i=lk[q[k]];i;i=e[i].nxt)
if(e[i].v && dstc[q[k]]+e[i].u<dstc[e[i].y]){
dstc[e[i].y]=dstc[q[k]]+e[i].u;
lst[e[i].y]=q[k],lse[e[i].y]=i;
if(!vstd[e[i].y]){
q[++hd]=e[i].y;
vstd[e[i].y]=true;
}
}
vstd[q[k]]=false;
}
//return dstc[t]; 注意不是判断dstc[t]不为0
return dstc[t]!=oo;
}
LL cstflw(){
LL bwl=0;
while(spfa()){
int flw=oo;
for(int i=t;i!=s;i=lst[i])
flw=min(flw,e[lse[i]].v);
for(int i=t;i!=s;i=lst[i]){
bwl+=flw*e[lse[i]].u;
e[lse[i]].v-=flw,e[lse[i]^1].v+=flw;
//cout<<i<<"<-";
}
//cout<<endl;
}
return bwl;
}

线筛求质数

1
2
3
4
5
6
7
8
9
10
int s[1100000];
void gtprm(){
for(int i=2;i<=m;++i){
if(!flg[i]) prm[++prt]=i;
for(int j=1;j<=prt && i*prm[j]<=m;++j){
flg[i*prm[j]]=true;
if(!(i%prm[j])) break;
}
}
}

splay(文艺平衡树,区间反转)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
struct nds{
int f,c[2];
int v,s;
int d;
nds(){
f=0,c[0]=0,c[1]=0;
v=0,s=0;
d=0;
}
}t[110000]; int tt=0,rt=0;
int n,m,a[110000];
//pushup
void psu(int x){
t[x].s=t[t[x].c[0]].s+t[t[x].c[1]].s+1;
}
//pushdown
void psd(int x){
if(!t[x].d) return ;
int l=t[x].c[0],r=t[x].c[1];
t[l].d^=1,t[r].d^=1;
t[x].d=0;
swap(t[x].c[0],t[x].c[1]);
}
//rotate
void rtt(int x,int w){
int y=t[x].f;
int z=t[y].f;
int r=(t[y].c[0]==x);
int l=(r^1);
if(z) t[z].c[t[z].c[1]==y]=x;
else rt=x;
t[t[x].c[r]].f=y,t[y].f=x,t[x].f=z;
t[y].c[l]=t[x].c[r],t[x].c[r]=y;
psu(y),psu(x);
}
//splay
void spl(int x,int w){
int y,z;
while(t[x].f!=w){
y=t[x].f;
z=t[y].f;
if(t[y].f!=w) rtt(((t[y].c[0]==x)^(t[z].c[0]==y)) ? x : y,w);
rtt(x,w);
}
}
//select
int slc(int x,int w){
if(!x) return 0;
psd(x); //注意pushdown
if(w<=t[t[x].c[0]].s) return slc(t[x].c[0],w);
else if(w==t[t[x].c[0]].s+1) return x;
else return slc(t[x].c[1],w-t[t[x].c[0]].s-1);
}
//estabilsh
int est(int l,int r,int y){
if(l>r) return 0;
int md=(l+r)>>1;
int x=++tt;
t[x].f=y,t[x].c[0]=0,t[x].c[1]=0;
t[x].v=a[md],t[x].s=1;
t[x].d=0;
if(md-1>=l) t[x].c[0]=est(l,md-1,x);
if(r>=md+1) t[x].c[1]=est(md+1,r,x);
psu(x);
return x;
}
void iod(int x){
if(!x) return ;
psd(x);
if(t[x].c[0]) iod(t[x].c[0]);
printf("%d ",t[x].v);
if(t[x].c[1]) iod(t[x].c[1]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i) a[i]=i;
rt=est(1,n,0);
int l,r;
while(m --> 0){
scanf("%d%d",&l,&r);
if(l==r) continue; //注意特判
//否则splay(y,x)出错
int x=slc(rt,l),y=slc(rt,r);
spl(x,0),spl(y,x);
swap(t[x].v,t[y].v); //画图即懂
t[t[y].c[0]].d^=1; //注意不是t[r]
}
iod(rt);
return 0;
}

堆优化的 Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;
// 注意必须要有greater,否则搞出来是大根堆!!
void dij(int x){
for(int i=1;i<=n;i++){
dst[i]=ooo;
vis[i]=0;
}
dst[x]=0;
q.push({0,x});
while(q.size()>0){
x=q.top().second; // 复用x警告
q.pop();
if(vis[x]) continue;
vis[x]=1;
// 要用vis数组,不要用dst大小比较,否则复杂度不对
for(auto i:e[x]){
if(dst[x]+i.second<dst[i.first]){
dst[i.first]=dst[x]+i.second;
q.push({dst[i.first],i.first});
}
}
}
}

最小环

无向图:暴力删每一条边,然后看这条边起点到终点的最短路,复杂度 O(m(n+m)logm)。

有向图:如果边都是正权而且允许 2 个点的环,先用 dij 求任意两点之间最短路,然后边的终点到起点的最短路+边的长度更新答案,复杂度 O(n(n+m)logm)。

这两种方法有微小的复杂度差异,如果能写下面时写了上面会被 cjb 卡。

圆方树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include<iostream>
#include<cstdio>
using namespace std;
struct edg{int nxt,y;}e[810000]; int lk[210000],lhd=0; //注意原图也要双倍
void ist(int x,int y){
e[++lhd]=(edg){lk[x],y}; lk[x]=lhd;
e[++lhd]=(edg){lk[y],x}; lk[y]=lhd;
}
edg g[810000]; int gk[210000],ghd=0;
void gst(int x,int y){
g[++ghd]=(edg){gk[x],y}; gk[x]=ghd;
g[++ghd]=(edg){gk[y],x}; gk[y]=ghd;
}
int n,m,o;
int dfn[210000],low[210000],dfc=0; //注意开双倍,因为有两种点
int q[210000],hd;
int cnt=0;
int s[210000];
int f[210000],ft=0;
int ast[210000][20];
int dp[210000];
void tj(int x){
dfn[x]=++dfc;
low[x]=dfc;
q[++hd]=x;
for(int i=lk[x];i;i=e[i].nxt){
if(!dfn[e[i].y]){
tj(e[i].y);
low[x]=min(low[x],low[e[i].y]);
if(low[e[i].y]==dfn[x]){ //找到一个点双
++cnt; //增加方点个数
for(int j=0;j!=e[i].y;--hd){ //将点双中除了u的点退栈,并在圆方树中连边
j=q[hd];
gst(cnt,j);
}
gst(cnt,x); //u自身也要连边,但不退栈
}
}
else{
low[x]=min(low[x],dfn[e[i].y]);
}
}
}
void gte(){ //从临时图g转移到常用图e
for(int i=1;i<=cnt;++i) lk[i]=gk[i];
for(int i=1;i<=ghd;++i) e[i]=g[i];
lhd=ghd;
}
void dfs(int x,int y){
f[x]=ft;
s[x]=s[y];
if(x<=n) s[x]++;
dp[x]=dp[y]+1;
ast[x][0]=y;
for(int i=1;(1<<i)<=dp[x];++i) ast[x][i]=ast[ast[x][i-1]][i-1];
for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y){
dfs(e[i].y,x);
}
}
int lca(int x,int y){
if(dp[x]<dp[y]) swap(x,y);
int tmp=dp[x]-dp[y];
for(int i=0;i<=19;++i)if((1<<i)&tmp) x=ast[x][i];
for(int i=16;i>=0;--i)if(ast[x][i]!=ast[y][i]){
x=ast[x][i];
y=ast[y][i];
}
if(x==y) return x;
else return ast[x][0];
}
int main(){
scanf("%d%d",&n,&m);
cnt=n;
int l,r;
for(int i=1;i<=m;++i){
scanf("%d%d",&l,&r);
ist(l,r);
}
for(int i=1;i<=n;++i)if(!dfn[i]){
tj(i);
--hd; //dfs完了还有一个根,要退栈
}
gte();
for(int i=1;i<=n;++i)if(f[i]==0){
ft++;
dfs(i,0);
}
scanf("%d",&o);
while(o --> 0){
scanf("%d%d",&l,&r);
int u=lca(l,r);
printf("%d\n",s[l]+s[r]-s[u]-s[ast[u][0]]);
}
return 0;
}

平面最近点对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const double oo=1e16;
struct nds{double x,y;}a[210000];
int n;
nds b[210000];
nds q[210000]; int hd=0,tl=1;
inline double sqr(double x){ return x*x;}
inline double dst(nds x,nds y){
return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
double dvs(int l,int r){
if(l==r) return oo;
if(l+1==r){
if(a[l].y>a[r].y) swap(a[l],a[r]); //记得两个点也要排序
return dst(a[l],a[r]);
}
int md=(l+r)>>1;
double mdx=a[md].x; //注意记录中点坐标,否则排完序就错了
double d=min(dvs(l,md),dvs(md+1,r));
int hd1=l,hd2=md+1;
for(int i=l;i<=r;++i){
if(hd1>md) b[i]=a[hd2++];
else if(hd2>r) b[i]=a[hd1++];
else if(a[hd1].y<a[hd2].y) b[i]=a[hd1++];
else b[i]=a[hd2++];
}
for(int i=l;i<=r;++i) a[i]=b[i];
double mn=d; //注意初值是d而不是oo
hd=0,tl=1;
for(int i=l;i<=r;++i)if(fabs(a[i].x-mdx)<d){
q[++hd]=a[i];
while(fabs(q[tl].y-q[hd].y)>d) tl++;
for(int j=tl;j<hd;++j) mn=min(mn,dst(q[j],a[i]));
}
return mn;
}
bool cmp(nds x,nds y){
return x.x<y.x;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%lf%lf",&a[i].x,&a[i].y);
}
sort(a+1,a+n+1,cmp);
printf("%.4lf\n",dvs(1,n));
return 0;
}

KMBFS(严格n^3)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
ll s[410];
ll e[410][410];
//e[i][j]是左边第i个和右边第j个匹配的贡献
int prv[410],nxt[410];
//算法跑完后nxt就是左边匹配的右边
//如果nxt[i]为0就表示没匹配
ll slc[410];
ll dbx[410],dby[410];
bool vst[410];
void bfs(int x){
int px=0,py=0,yy=0;
ll d=oo;
for(int i=1;i<=n;++i){
prv[i]=0;
slc[i]=oo;
}
nxt[py]=x;
do{
px=nxt[py];
d=oo;
vst[py]=1;
for(int i=1;i<=n;++i)if(vst[i]==0){
if(slc[i]>dbx[px]+dby[i]-e[px][i]){
slc[i]=dbx[px]+dby[i]-e[px][i];
prv[i]=py;
}
if(slc[i]<d){
d=slc[i];
yy=i;
}
}
for(int i=0;i<=n;++i){
if(vst[i]){
dbx[nxt[i]]-=d;
dby[i]+=d;
}
else slc[i]-=d;
}
py=yy;
}while(nxt[py]!=0);
while(py){
nxt[py]=nxt[prv[py]];
py=prv[py];
}
}
void km(){
for(int i=1;i<=n;++i){
dbx[i]=0;
dby[i]=0;
nxt[i]=0;
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j) vst[j]=0;
bfs(i);
}
}
int main(){
e[i][j]=s[bsc(b[i]+c[j])];
km();
ll bwl=0;
for(int i=1;i<=n;++i)if(nxt[i]!=0)
bwl+=e[nxt[i]][i];
printf("%lld\n",bwl);

}

二次剩余(Python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from random import randint


def mul_i(a, b, t, p):
return [(a[0] * b[0] + a[1] * b[1] * t) % p, (a[0] * b[1] + b[0] * a[1]) % p]


def pow_i(a, b, c, t, p):
ans = [1, 0]
z = [a, b]
while c > 0:
if c % 2 == 1:
ans = mul_i(ans, z, t, p)
z = mul_i(z, z, t, p)
c = c // 2

return ans


def legendre(a, p):
return pow(a, (p - 1) // 2, p)


def residue(n, p):
t = randint(0, p - 1)
while legendre(t ** 2 - n, p) != p - 1:
t = randint(0, p - 1)

a = pow_i(t, 1, (p + 1) // 2, t ** 2 - n, p)
return a[0]


if __name__ == '__main__':
T = int(input())
for t in range(T):
n, p = [int(i) for i in input().split(' ')]
if legendre(n, p) == p - 1:
print('No solution!')
elif legendre(n, p) == 0:
print(0)
else:
a = residue(n, p)
b = p - a
if a > b:
a, b = b, a
if a == b:
print(a)
else:
print(a, b)

BSGS 和扩展 BSGS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
ll gcd(ll x,ll y){  return y ? gcd(y,x%y) : x;}
ll qcp(ll x,ll y,ll z){
ll bwl=1;
for(;y;y>>=1){
if(y&1) bwl=bwl*x%z;
x=x*x%z;
}
return bwl;
}
ll bsgs(ll x,ll y,ll z){
x%=z,y%=z;
if(y==1) return 0;
if(x==0 && y==0) return 1;
if(x==0 && y!=0) return -1;
map<ll,ll> tong;
ll w=sqrt(z)+1;
for(ll i=0,j=y;i<w;i++,j=j*x%z) tong[j]=i;
ll k=qcp(x,w,z);
for(ll i=1,j=k;i<=w+1;i++,j=j*k%z){
if(tong.count(j)) return i*w-tong[j];
}
return -1;
}
ll exbsgs(ll x,ll y,ll z){
x%=z,y%=z;
if(y==1) return 0;
ll k=0,bwl=1;
for(ll d=gcd(x,z);d!=1;d=gcd(x,z)){
if(y%d) return -1;
y/=d,z/=d;
k++,bwl=bwl*x/d%z;
if(y==bwl) return k;
}
map<ll,ll> tong;
ll w=sqrt(z)+1;
for(int i=0,j=y;i<w;i++,j=j*x%z) tong[j]=i;
ll u=qcp(x,w,z);
for(int i=1,j=bwl*u%z;i<=w+1;i++,j=j*u%z){
if(tong.count(j)) return i*w-tong[j]+k;
}
return -1;
}

分治 FFT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int mxn=1e5;
const ll mo=998244353;
int n;
ll a[mxn+5],b[mxn+5];
ll A[4*mxn+5],B[4*mxn+5];
int rvs[4*mxn+5],dg[32],N,L;
ll _1_N;
ll qcp(ll x,ll y){
ll z=1;
for(;y;y>>=1){
if(y&1) z=(z*x)%mo;
x=(x*x)%mo;
}
return z;
}
void ntt(ll x[],ll mk){
for(int i=0;i<N;i++)if(i<rvs[i]) swap(x[i],x[rvs[i]]);
for(int i=2;i<=N;i<<=1){
ll wn=qcp(3,(mk*((mo-1)/i))%(mo-1));
for(int k=0;k<N;k+=i){
ll w=1;
for(int j=k;j<k+(i>>1);j++){
ll _x=x[j],_y=(x[j+(i>>1)]*w)%mo;
x[j]=(_x+_y)%mo,x[j+(i>>1)]=(_x-_y+mo)%mo;
w=(w*wn)%mo;
}
}
}
if(mk==mo-2) for(int i=0;i<N;i++) x[i]=(x[i]*_1_N)%mo;
}
void pre(int l){
for(N=1,L=0;N<=l;N<<=1,++L);
N<<=1,++L;
_1_N=qcp(N,mo-2);
for(int i=0;i<N;i++){
rvs[i]=(rvs[i>>1]>>1)|((i&1)<<(L-1));
}
}
void fz(int l,int r){
if(l>=r) return ;
int md=(l+r)>>1;
fz(l,md);
pre(r-l+1);
for(int i=0;i<N;i++){
A[i]=0;
B[i]=0;
}
for(int i=l;i<=md;i++) A[i-l]=a[i];
for(int i=1;i<=r-l;i++) B[i-1]=b[i];
ntt(A,1);
ntt(B,1);
for(int i=0;i<N;i++){
A[i]*=B[i];
A[i]%=mo;
}
ntt(A,mo-2);
for(int i=md+1;i<=r;i++){
a[i]+=A[i-l-1];
a[i]%=mo;
}
fz(md+1,r);
}
int main(){
cin.tie(0)->sync_with_stdio(false);
cin>>n;
for(int i=1;i<n;i++) cin>>b[i];
a[0]=1;
fz(0,n-1);
for(int i=0;i<n;i++) cout<<a[i]<<" ";
cout<<endl;
return 0;
}

多项式求逆元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void get_inv(ll *A,ll *B,int deg){
if(deg==1){
B[0]=inv(A[0]);
return;
}
get_inv(A,B,(deg+1)>>1);
for(limit=1;limit<=(deg<<1);limit<<=1);
for(int i=0;i<limit;i++){
R[i]=(R[i>>1]>>1)|((i&1)?(limit>>1):0);
C[i]=(i<deg?A[i]:0);
}
NTT(C,1),NTT(B,1);
for(int i=0;i<limit;i++){
B[i]=(2ll-C[i]*B[i]%p+p)%p*B[i]%p;
}
NTT(B,-1);
fill(B+deg,B+limit,0);
}

LCT(弹飞绵羊)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
const int mxn=2e5;
int n,m,a[mxn+5];
int c[mxn+5][2],fa[mxn+5],rv[mxn+5];
int st[mxn+5],tp=0;
int sz[mxn+5];
bool isr(int x){
return c[fa[x]][0]!=x && c[fa[x]][1]!=x;
}
void upd(int x){
sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;
}
void psd(int x){
int l=c[x][0],r=c[x][1];
if(rv[x]){
rv[x]=0;
rv[l]^=1,rv[r]^=1;
swap(c[x][0],c[x][1]);
}
}
void rtt(int x){
int y=fa[x];
int z=fa[y];
int l=(c[y][1]==x);
int r=l^1;
if(!isr(y)) c[z][c[z][1]==y]=x;
fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
c[y][l]=c[x][r];
c[x][r]=y;
upd(y);
upd(x);
}
void spl(int x){
tp=0;
st[++tp]=x;
for(int i=x;!isr(i);i=fa[i]) st[++tp]=fa[i];
for(int i=tp;i;i--) psd(st[i]);
while(!isr(x)){
int y=fa[x];
int z=fa[y];
if(!isr(y)) rtt((c[y][0]==x)^(c[z][0]==y)?x:y);
rtt(x);
}
}
void acc(int x){
int lst=0;
while(x){
spl(x);
c[x][1]=lst;
upd(x);
lst=x;
x=fa[x];
}
}
void mkr(int x){
acc(x);
spl(x);
rv[x]^=1;
}
int fdt(int x){
acc(x);
spl(x);
while(c[x][0]) x=c[x][0];
return x;
}
void cnn(int x,int y){
//cout<<"cnn: "<<x<<" "<<y<<endl;
if(fdt(x)==fdt(y)) return;
mkr(x);
fa[x]=y;
spl(x);
upd(x);
upd(y);
}
void cut(int x,int y){
//cout<<"cut: "<<x<<" "<<y<<endl;
if(fdt(x)!=fdt(y)) return;
mkr(x);
acc(y);
spl(y);
if(c[x][1]) return;
c[y][0]=0,fa[x]=0;
upd(x);
upd(y);
}

Splay(维修数列)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include<bits/stdc++.h>
using namespace std;
const int oo=1e9;
const int mxn=5e6;
int n,m;
int a[mxn+5];
int rt,nt,fa[mxn+5],c[mxn+5][2];
int sz[mxn+5];
int rv[mxn+5],dt[mxn+5];
int v[mxn+5];
int sm[mxn+5],mx[mxn+5],lx[mxn+5],rx[mxn+5];
void upd(int x){
int l=c[x][0],r=c[x][1];
sm[x]=sm[l]+sm[r]+v[x];
sz[x]=sz[l]+sz[r]+1;
mx[x]=max(max(mx[l],mx[r]),rx[l]+v[x]+lx[r]);
lx[x]=max(lx[l],sm[l]+v[x]+lx[r]);
rx[x]=max(rx[r],rx[l]+v[x]+sm[r]);
}
void mdx(int x,int y){
dt[x]=1,v[x]=y,sm[x]=y*sz[x];
if(v[x]>0) lx[x]=sm[x],rx[x]=sm[x],mx[x]=sm[x];
else lx[x]=0,rx[x]=0,mx[x]=v[x];
// At least 1 number.
}
void mdr(int x){
rv[x]^=1;
swap(lx[x],rx[x]);
swap(c[x][0],c[x][1]);
}
void psd(int x){
int l=c[x][0],r=c[x][1];
if(dt[x]){
// "dt[x]!=v[x]", attention!
dt[x]=0;
if(l) mdx(l,v[x]);
if(r) mdx(r,v[x]);
}
if(rv[x]){
rv[x]=0;
mdr(l),mdr(r);
}
}
void rtt(int x,int &g){
int y=fa[x];
int z=fa[y];
int l=(c[y][1]==x);
int r=l^1;
if(y==g) g=x;
else c[z][c[z][1]==y]=x;
fa[c[x][r]]=y,fa[y]=x,fa[x]=z;
c[y][l]=c[x][r],c[x][r]=y;
// Attention, "y" first "x" second.
upd(y),upd(x);
}
void spl(int x,int &g){
while(x!=g){
int y=fa[x];
int z=fa[y];
if(y!=g){
rtt((c[y][0]==x)^(c[z][0]==y)?x:y,g);
}
rtt(x,g);
}
}
int fnd(int x,int y){
psd(x);
int l=c[x][0],r=c[x][1];
while(sz[l]+1!=y){
if(y<=sz[l]) x=l;
else y-=sz[l]+1,x=r;
psd(x);
l=c[x][0],r=c[x][1];
}
return x;
}
int spt(int l,int r){
// There are 2 additional nodes: "a[1],a[n+2]".
int x=fnd(rt,l),y=fnd(rt,r+2);
spl(x,rt);
spl(y,c[x][1]);
return c[y][0];
}
int bd(int l,int r,int y){
if(l>r) return 0;
int md=(l+r)>>1;
int x=++nt;
if(l!=r){
c[x][0]=bd(l,md-1,x);
c[x][1]=bd(md+1,r,x);
}
v[x]=a[md],fa[x]=y;
upd(x);
return x;
}
void ist(int l,int r){
spt(l+1,l);
int y=c[rt][1];
c[y][0]=bd(1,r,y);
upd(y);
upd(fa[y]);
}
void dlt(int l,int r){
int x=spt(l,r);
int y=fa[x];
c[y][c[y][1]==x]=0;
fa[x]=0;
upd(y);
upd(fa[y]);
}
void mdf(int l,int r,int z){
int x=spt(l,r);
int y=fa[x];
mdx(x,z);
upd(y);
upd(fa[y]);
}
void rvs(int l,int r){
int x=spt(l,r);
int y=fa[x];
mdr(x);
upd(y);
upd(fa[y]);
}
int rqs(int l,int r){
return sm[spt(l,r)];
}

长链剖分(谈笑风生)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mxn=3e5+10;
int n,m;
vector<pair<int,int>> q[mxn];
vector<int> e[mxn];
int fa[mxn],dp[mxn],ds[mxn],sz[mxn];
int hc[mxn],tp[mxn];
ll *f[mxn],*g[mxn];
ll ans[mxn];
void dfs1(int x,int y){
fa[x]=y;
dp[x]=dp[y]+1;
ds[x]=1;
sz[x]=1;
for(auto i:e[x]){
if(i==y) continue;
dfs1(i,x);
ds[x]=max(ds[x],ds[i]+1);
sz[x]+=sz[i];
}
}
void dfs2(int x,int y,int z){
tp[x]=z;
for(auto i:e[x]){
if(i==y) continue;
if(ds[i]>ds[hc[x]]) hc[x]=i;
}
if(hc[x]==0) return;
dfs2(hc[x],x,z);
for(auto i:e[x]){
if(i==y || i==hc[x]) continue;
dfs2(i,x,i);
}
}
void dfs3(int x,int y){
if(x==tp[x]){
f[x]=(ll*)malloc((ds[x]+1)*sizeof(ll));
g[x]=(ll*)malloc((ds[x]+1)*sizeof(ll));
for(int i=0;i<=ds[x];i++){
f[x][i]=0;
g[x][i]=0;
}
}
else{
f[x]=f[y]+1;
g[x]=g[y]+1;
}
f[x][0]=sz[x]-1;
g[x][0]=sz[x]-1;
if(hc[x]==0) return;
dfs3(hc[x],x);
for(auto i:e[x]){
if(i==y || i==hc[x]) continue;
dfs3(i,x);
for(int j=ds[i]-1;j>=0;j--){
f[x][j+1]+=f[i][j];
g[x][j+1]=f[x][j+1]+g[x][j+2];
}
}
g[x][0]=f[x][0]+g[x][1];
for(auto i:q[x]){
ans[i.second]+=g[x][1]-g[x][min(i.first+1,ds[x])];
ans[i.second]+=(ll)min(dp[x]-1,i.first)*(sz[x]-1);
}
}
int main(){
cin.tie(0)->sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<n;i++){
int l,r;
cin>>l>>r;
e[l].push_back(r);
e[r].push_back(l);
}
for(int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
q[l].push_back({r,i});
}
dfs1(1,0);
dfs2(1,0,1);
dfs3(1,0);
for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
return 0;
}

动态 DP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll oo=1e18;
struct mat{
ll v[2][2];
mat(){
v[0][0]=0,v[0][1]=0,v[1][0]=0,v[1][1]=0;
}
mat(ll v1,ll v2,ll v3,ll v4){
v[0][0]=v1,v[0][1]=v2,v[1][0]=v3,v[1][1]=v4;
}
};
int n,m;
ll a[110000];
vector<int> e[110000];
int sz[110000],dp[110000],fa[110000];
int hc[110000],tp[110000],ed[110000];
int dfn[110000],dfa[110000],dft=0;
ll f[110000][2],g[110000][2];
mat v[410000];
mat operator*(mat x,mat y){
mat z;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
z.v[i][j]=-oo;
for(int k=0;k<2;k++){
z.v[i][j]=max(z.v[i][j],x.v[i][k]+y.v[k][j]);
}
}
}
return z;
}
mat mkm(int x){
return mat(g[x][0],g[x][0],g[x][1],-oo);
}
void psu(int x){
v[x]=v[x<<1]*v[x<<1|1];
}
void gts(int x,int l,int r){
if(l==r){
v[x]=mkm(dfa[l]);
return ;
}
int md=(l+r)>>1;
gts(x<<1,l,md);
gts(x<<1|1,md+1,r);
psu(x);
}
void mdf(int x,int l,int r,int y,mat z){
if(l==r){
v[x]=z;
return ;
}
int md=(l+r)>>1;
if(y<=md) mdf(x<<1,l,md,y,z);
else mdf(x<<1|1,md+1,r,y,z);
psu(x);
}
mat qry(int x,int l,int r,int ql,int qr){
if(l==ql && r==qr) return v[x];
int md=(l+r)>>1;
if(ql<=md && qr>md){
return qry(x<<1,l,md,ql,md)*qry(x<<1|1,md+1,r,md+1,qr);
}
else if(qr<=md){
return qry(x<<1,l,md,ql,qr);
}
else{
return qry(x<<1|1,md+1,r,ql,qr);
}
}
void dfs1(int x,int y){
fa[x]=y;
dp[x]=dp[y]+1;
sz[x]=1;
for(auto i:e[x]){
if(i==y) continue;
dfs1(i,x);
sz[x]+=sz[i];
}
}
void dfs2(int x,int y,int z){
dfa[++dft]=x;
dfn[x]=dft;
tp[x]=z;
ed[z]=x;
int mi=0;
for(auto i:e[x]){
if(i==y) continue;
if(sz[i]>sz[mi]) mi=i;
}
if(mi==0) return;
hc[x]=mi;
dfs2(hc[x],x,z);
for(auto i:e[x]){
if(i==y || i==hc[x]) continue;
dfs2(i,x,i);
}
}
void dfs3(int x,int y){
f[x][0]=0,f[x][1]=a[x];
g[x][0]=0,g[x][1]=a[x];
if(hc[x]==0) return;
for(auto i:e[x]){
if(i==fa[x]) continue;
dfs3(i,x);
f[x][0]+=max(f[i][0],f[i][1]);
f[x][1]+=f[i][0];
}
g[x][0]=f[x][0]-max(f[hc[x]][0],f[hc[x]][1]);
g[x][1]=f[x][1]-f[hc[x]][0];
}
void upd(int x,ll y){
g[x][1]+=y-a[x];
a[x]=y;
for(;x;){
mat sum1=qry(1,1,n,dfn[tp[x]],dfn[ed[tp[x]]]);
mdf(1,1,n,dfn[x],mkm(x));
mat sum2=qry(1,1,n,dfn[tp[x]],dfn[ed[tp[x]]]);
if(fa[tp[x]]){
g[fa[tp[x]]][0]+=max(sum2.v[0][0],sum2.v[1][0])-max(sum1.v[0][0],sum1.v[1][0]);
g[fa[tp[x]]][1]+=sum2.v[0][0]-sum1.v[0][0];
}
x=fa[tp[x]];
}
}
int main(){
cin.tie(0)->sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++){
int l,r;
cin>>l>>r;
e[l].push_back(r);
e[r].push_back(l);
}
dfs1(1,0);
dfs2(1,0,1);
dfs3(1,0);
gts(1,1,n);
for(int i=1;i<=m;i++){
int l;
ll r;
cin>>l>>r;
upd(l,r);
mat sum=qry(1,1,n,dfn[1],dfn[ed[1]]);
cout<<max(sum.v[0][0],sum.v[1][0])<<endl;
}
return 0;
}

虚树(消耗战)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll oo=1e18;
int n,m,o;
int a[310000],b[310000];
vector<pair<int,ll>> e1[310000],e2[310000];
int acc[310000][30];
int dfn[310000],dft=0;
ll dis[310000],dp[310000];
vector<int> q;
void dfs1(int x,int y,int z){
dp[x]=z;
dfn[x]=++dft;
acc[x][1]=y;
for(int i=2;i<=20;i++) acc[x][i]=acc[acc[x][i-1]][i-1];
for(auto i:e1[x]){
if(i.first==y) continue;
dis[i.first]=min(dis[x],i.second);
dfs1(i.first,x,z+1);
}
}
int lca(int x,int y){
if(dp[x]<dp[y]) swap(x,y);
for(int i=20;i>=1;i--){
if(dp[acc[x][i]]>=dp[y]){
x=acc[x][i];
}
}
for(int i=20;i>=1;i--){
if(acc[x][i]!=acc[y][i]){
x=acc[x][i];
y=acc[y][i];
}
}
return x==y ? x : acc[x][1];
}
void ist2(int x,int y){
if(dp[x]>y) swap(x,y);
e2[x].push_back({y,dis[y]});
e2[y].push_back({x,dis[y]});
}
bool cmp(int x,int y){
return dfn[x]<dfn[y];
}
void bdt(){
sort(a+1,a+o+1,cmp);
q.clear();
for(int i=1;i<=o;i++) q.push_back(a[i]);
for(int i=2;i<=o;i++) q.push_back(lca(a[i],a[i-1]));
q.push_back(1);
sort(q.begin(),q.end(),cmp);
q.resize(distance(q.begin(),unique(q.begin(),q.end())));
for(auto i:q) e2[i].clear();
for(int i=1;(unsigned int)i<q.size();i++){
ist2(lca(q[i],q[i-1]),q[i]);
}
}
ll dfs2(int x,int y,ll z){
if(b[x]==1) return z;
ll sum=0;
for(auto i:e2[x]){
if(i.first==y) continue;
sum+=dfs2(i.first,x,i.second);
}
return min(sum,z);
}
int main(){
cin.tie(0)->sync_with_stdio(false);
cin>>n;
int l,r;
ll v;
for(int i=1;i<n;i++){
cin>>l>>r>>v;
e1[l].push_back({r,v});
e1[r].push_back({l,v});
}
dis[1]=oo;
dfs1(1,0,1);
cin>>m;
while(m --> 0){
cin>>o;
for(int i=1;i<=o;i++) cin>>a[i];
for(int i=1;i<=o;i++) b[a[i]]=1;
bdt();
cout<<dfs2(1,0,oo)<<endl;
for(int i=1;i<=o;i++) b[a[i]]=0;
}
return 0;
}

点分治

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ip;
vector<ip> e[11000];
int n,m;
int b[11000];
int ans[11000];
int sz[11000],dp[11000];
bool flg[11000];
bool f[11000000];
vector<vector<int>> q;
void dfs(int x,int y,vector<int> &tq){
tq.push_back(x);
sz[x]=1;
for(auto i:e[x]){
if(flg[i.first] || i.first==y) continue;
dp[i.first]=dp[x]+i.second;
dfs(i.first,x,tq);
sz[x]+=sz[i.first];
}
}
ip fdc(int x,int y,int z){
ip ret={x,z-sz[x]};
for(auto i:e[x]){
if(flg[i.first] || i.first==y) continue;
ret.second=max(ret.second,sz[i.first]);
}
for(auto i:e[x]){
if(flg[i.first] || i.first==y) continue;
ip stc=fdc(i.first,x,z);
if(stc.second<ret.second){
ret=stc;
}
}
return ret;
}
void dfz(int x){
flg[x]=1;
q.clear();
for(auto i:e[x]){
if(flg[i.first]) continue;
dp[i.first]=i.second;
vector<int> tq={};
dfs(i.first,x,tq);
q.push_back(tq);
}
f[0]=1;
for(auto i:q){
for(auto j:i){
for(int k=1;k<=m;k++){
if(b[k]>=dp[j] && f[b[k]-dp[j]]==1){
ans[k]++;
}
}
}
for(auto j:i){
if(dp[j]<=10000000){
f[dp[j]]=1;
}
}
}
for(auto i:q){
for(auto j:i){
if(dp[j]<=10000000){
f[dp[j]]=0;
}
}
}
f[0]=0;
for(auto i:e[x]){
if(flg[i.first]) continue;
dfz(fdc(i.first,0,sz[i.first]).first);
}
}
int main(){
cin.tie(0)->sync_with_stdio(false);
cin>>n>>m;
int l,r,v;
for(int i=1;i<n;i++){
cin>>l>>r>>v;
e[l].push_back({r,v});
e[r].push_back({l,v});
}
for(int i=1;i<=m;i++) cin>>b[i];
dfz(1);
for(int i=1;i<=m;i++){
cout<<(ans[i]>0?"AYE":"NAY")<<endl;
}
return 0;
}

>w<