寒假集训纪要
1.28
KMP算法
匹配
点击查看代码
int j;
j=0;
for(int i=1;i<=la;++i)
{
while(j && b[j+1]!=a[i]) j=next[j];
if(b[j+1]==a[j]) j++;
if(j==lb)
{
cout<<i-lb+1<<'\n';
j=next[j];
}
}
处理 next 数组
点击查看代码
j=0;
for(int i=2;i<=lb;++i)
{
while(j && b[i]!=b[j+1])
j=next[j];
if(b[j+1]==b[j]) j++;
next[i]=j;
}
洛谷模板
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
int la,lb,next_[N],j;
char a[N],b[N];
signed main()
{
cin>>a+1;
cin>>b+1;
la=strlen(a+1);
lb=strlen(b+1);
for(int i=2;i<=lb;++i)
{
while(j && b[i]!=b[j+1])
j=next_[j];
if(b[j+1]==b[i]) j++;
next_[i]=j;
}
j=0;
for(int i=1;i<=la;++i)
{
while(j>0 && b[j+1]!=a[i]) j=next_[j];
if(b[j+1]==a[i]) j++;
if(j==lb)
{
cout<<i-lb+1<<'\n';
j=next_[j];
}
}
for(int i=1;i<=lb;++i)
cout<<next_[i]<<" ";
}
动物园
有趣的题
预处理串的长度然后 num 数组按题意模拟即可(不是
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int la,lb,next_[N],n;
int sum[N];
char a[N];
signed main()
{
cin>>n;
while(n--)
{
memset(next_,0,sizeof(next_));
memset(sum,0,sizeof(sum));
cin>>a+1;
la=strlen(a+1);
int ans=1;
sum[1]=1,next_[1]=0;
for(int i=2,j=0;i<=la;++i)
{
while(j && a[i]!=a[j+1])
j=next_[j];
if(a[j+1]==a[i]) j++;
next_[i]=j;
sum[i]=sum[j]+1;
}
for(int i=1,j=0;i<=la;++i)
{
while(j>0 && a[j+1]!=a[i]) j=next_[j];
if(a[j+1]==a[i]) j++;
while(j>i/2) j=next_[j];
ans=(ans*(sum[j]+1))%p;
}
cout<<ans<<'\n';
}
}
Censoring S
KMP删除操作,栈模拟,如果匹配到了子串就出栈即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int la,lb,next_[N],n;
int pos[N],top,sta[N];
char a[N],b[N];
signed main()
{
cin>>a+1>>b+1;
int la=strlen(a+1),lb=strlen(b+1);
for(int i=2,j=0;i<=lb;++i)
{
while(j && b[i]!=b[j+1])
j=next_[j];
if(b[j+1]==b[i]) j++;
next_[i]=j;
}
for(int i=1,j=0;i<=la;++i)
{
while(j && a[i]!=b[j+1]) j=next_[j];
if(b[j+1]==a[i]) j++;
pos[i]=j;
sta[++top]=i;
if(j==lb) top-=lb,j=pos[sta[top]];
}
for(int i=1;i<=top;++i)
cout<<a[sta[i]];
}
【XR-3】系统设计
写的最久的题,挑了一下午发现线段树写假了😅😅😅
线段树上哈希(?),看着题解过了,大概算是懂了吧。
点击查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int unsigned long long
#define mid ((l+r)>>1)
#define ls (p<<1)
#define rs (p<<1|1)
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}if(cnt==0)putchar('0');while(cnt>0)putchar(F[--cnt]);putchar(' ');}
}
using namespace std;
using namespace __gnu_pbds;
using namespace IO;
const int N=1e6;
const int base=2e6+3;
int n,m,T,ans,root,fa[N],cur,len,t[N<<2],pri=229,a[N],sx[N],Pow[N];
vector<int> num[N];
cc_hash_table<int,int> q;
int op,x,l,r;
inline void dfs(int x,int fa)
{
q[sx[x]]=x;
for(int i=0,y;i<num[x].size();++i)
if((y=num[x][i])!=fa)
sx[y]=sx[x]*base+i+1+pri,dfs(y,x);
}
inline void pushup(int p,int len)
{
t[p]=t[ls]*Pow[len]+t[rs];
}
void build(int p,int l,int r)
{
if(l==r)
{
t[p]=a[l]+pri;return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p,r-mid);
}
inline void Update(int p,int l,int r,int k,int d)
{
if(l==r)
{
t[p]=d+pri;
return;
}
k<=mid ? Update(ls,l,mid,k,d) : Update(rs,mid+1,r,k,d);
pushup(p,r-mid);
}
inline int ask(int p,int l,int r)
{
if(l==r) return l;
int x=cur*Pow[mid-l+1]+t[ls];
if(q.find(x)==q.end()) return ask(ls,l,mid);
cur=x;
return ask(rs,mid+1,r);
}
inline int Find(int p,int L,int R,int l,int r,int &o)
{
if(L<=l && r<=R)
{
int x=cur*Pow[r-l+1]+t[p];
if(q.find(x)==q.end())
{
o=1;
return ask(p,l,r);
}
cur=x;
return 0;
}
if(L>mid) return Find(rs,L,R,mid+1,r,o);
if(R<=mid) return Find(ls,L,R,l,mid,o);
int ans=Find(ls,L,R,l,mid,o);
return o ? ans : Find(rs,L,R,mid+1,r,o);
}
signed main()
{
n=read();m=read();T=read();
Pow[0]=1;
for(int i=1;i<N;++i)
Pow[i]=Pow[i-1]*base;
for(int i=1;i<=n;++i)
{
fa[i]=read();
if(!fa[i]) root=i;
else num[fa[i]].push_back(i);
}
for(int i=1;i<=m;++i)
a[i]=read();
for(int i=1;i<=n;++i)
sort(num[i].begin(),num[i].end());
dfs(root,0);
build(1,1,m);
while(T--)
{
op=read();
if(op==2)
{
l=read();x=read();Update(1,1,m,l,x);
}
else
{
x=read();l=read();r=read();
cur=sx[x];
int fl=0;Find(1,l,r,1,m,fl);
cout<<q[cur]<<'\n';
}
}
}
1.29
学习了 Trie 和 01-Trie,但是写的题都挺板的,可能是难题现在也写不了了吧。
OKR-Periods of Words
KMP,找到前缀后继续找前缀的前缀,因为 border 的一些性质可以得到字符串的最小 border.
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int n,lb,next_[N];
int ans;
int min_border[N];
char a[N];
signed main()
{
cin>>n;
cin>>a+1;
for(int i=2,j=0;i<=n;++i)
{
while(j && a[i]!=a[j+1])
j=next_[j];
if(a[j+1]==a[i]) j++;
next_[i]=j;
}
for(int i=1;i<=n;++i)
{
int j=i;
while(next_[j]) j=next_[j];
if(next_[i]) next_[i]=j;
ans+=(i-j);
}
cout<<ans;
}
Trie
最基础的板子(判断是否有 \(A\) 串为 \(B\) 串的前缀)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
const int p=1e9+7;
int n,tot,nxt[N],k,t;
int root,len;
int trie[N][30];
int f[N];
inline void insert(string s)
{
int len=s.size();
int root=1;
for(int i=0;i<len;++i)
{
int x=s[i]-'0';
if(!trie[root][x])
trie[root][x]=++tot;
root=trie[root][x];
}
f[root]=1;
}
inline int find(string s)
{
int len=s.size();
int root=1;
for(int i=0;i<len;++i)
{
int x=s[i]-'0';
if(!trie[root][x]) return 0;
root=trie[root][x];
if(f[root]) return 1;
}
return 1;
}
signed main()
{
cin>>t;
while(t--)
{
memset(trie,0,sizeof(trie));
memset(f,0,sizeof(f));
tot=1;
int ans=0;
cin>>n;
for(int i=1;i<=n;++i)
{
string s;
cin>>s;
if(find(s)) ans=1;
insert(s);
}
if(ans) cout<<"NO"<<'\n';
else cout<<"YES"<<'\n';
}
}
01-Trie
两点异或最大和
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
const int p=1e9+7;
int n,tot,nxt[N],k,t;
int root,ans;
int trie[N][2];
int s[N];
inline void insert(int x)
{
int root=0;
for(int i=31;i>=0;--i)
{
int c=(x>>i)&1;
if(!trie[root][c])
trie[root][c]=++tot;
root=trie[root][c];
}
}
inline int find(int x)
{
int root=0;
int ans=0;
for(int i=31;i>=0;--i)
{
int c=(x>>i)&1,o=c^1;
if(trie[root][o]) root=trie[root][o],ans=ans<<1|1;
else root=trie[root][c],ans<<=1;
}
return ans;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
int x;
cin>>x;
ans=max(ans,find(x));
insert(x);
}
cout<<ans;
}
边权异或最大值(放个前向星存图就行)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
const int p=1e9+7;
int n,tot,nxt[N],k,t;
int root;
int trie[N][2];
int s[N];
struct node
{
int to,next,w;
}e[2*N];
int head[N],cnt;
inline void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].next=head[u];
e[cnt].w=w;
head[u]=cnt;
}
inline void insert(int x)
{
int root=0;
for(int i=31;i>=0;--i)
{
int c=(x>>i)&1;
if(!trie[root][c])
trie[root][c]=++tot;
root=trie[root][c];
}
}
inline int find(int x)
{
int root=0;
int ans=0;
for(int i=31;i>=0;--i)
{
int c=(x>>i)&1,o=c^1;
if(trie[root][o]) root=trie[root][o],ans=ans<<1|1;
else root=trie[root][c],ans<<=1;
}
return ans;
}
int f[N];
inline void dfs(int x,int fa)
{
insert(f[x]);
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(fa==y) continue;
f[y]=f[x]^e[i].w;
dfs(y,x);
}
}
signed main()
{
cin>>n;
for(int i=1;i<n;++i)
{
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dfs(1,1);int ans=0;
for(int i=1;i<=n;++i)
ans=max(ans,find(f[i]));
cout<<ans;
}
Nikitosh 和异或
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n,a,ans=0;
cin>>n;
while(n--)
{
cin>>a;
ans|=a;
}
cout<<ans*2;
}
字符串匹配
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+50;
const int p=1e9+7;
int n,lb,nxt[N],k,s,t;
int c[N],ans[N];
int a[N],b[N],rk[N],rks[N],f[N];
inline int lowbit(int x){return x&(-x);}
inline void update(int p,int v){while(p<=s){c[p]+=v;p+=lowbit(p);}}
inline int ask(int p){int ans=0;while(p){ans+=c[p];p-=lowbit(p);}return ans;}
signed main()
{
cin>>n>>k>>s;
for(int i=0;i<n;++i)
cin>>a[i];
for(int i=0;i<k;++i)
{
cin>>b[i];
update(b[i],1);
rk[i]=ask(b[i]-1),rks[i]=ask(b[i]);
}
memset(c,0,sizeof(c));
for(int i=1,j;i<k;++i)
{
j=f[i];
update(b[i],1);
while(j && (ask(b[j]-1)!=rk[i] || ask(b[j])!=rks[i]))
{
for(int p=i-j;p<i-f[j];++p) update(b[p],-1);
j=f[j];
}
f[i+1]=(rk[j]==ask(b[i]-1) && rks[j]==ask(b[i])) ? j+1 : 0;
}
memset(c,0,sizeof(c));
for(int i=0,j=0;i<n;++i)
{
update(a[i],1);
while(j && (ask(a[i]-1)!=rk[j] || ask(a[i])!=rks[j]))
{
for(int p=i-j;p<i-f[j];++p) update(a[p],-1);
j=f[j];
}
if(ask(a[i]-1)==rk[j] && ask(a[i])==rks[j]) j++;
if(j==k)
{
ans[++t]=i-j+1;
for(int p=i-j+1;p<=i;++p)
update(a[p],-1);
j=0;
}
}
cout<<t<<"\n";
for(int i=1;i<=t;++i)
cout<<ans[i]+1<<"\n";
}
通配符匹配
做法有误,仅限于小数据,详见 1.30 闲话
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
int n,m,t;
char s[N],st[N];
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
bool check(int n,int m)
{
if(m==0)
{
for(int i=1;i<=n;++i)
if(s[i]!='*')
return 0;
return 1;
}
if(n==0) return 0;
if(s[n]!='*')
return (s[n]==st[m] || s[n]=='?') && check(n-1,m-1);
else
{
for(int i=m;i>=0;--i)
if(check(n-1,i))
return 1;
}
return 0;
}
signed main()
{
scanf("%s",s+1);
n=strlen(s+1);
t=read();
while(t--)
{
scanf("%s",st+1);
m=strlen(st+1);
cout<<(check(n,m) ? "YES" : "NO")<<'\n';
}
}
1.30
AC自动机
AC自动机简单版
模板,查询有多少个子串在文章中出现过
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=6e6+5;
int n,m,cnt;
char s[N];
namespace AC_automaton
{
queue<int> q;
struct tree
{
int son[26],flag,fail;
}trie[N];
inline void insert(char* s)
{
int u=1,len=strlen(s);
for(int i=0;i<len;++i)
{
int v=s[i]-'a';
if(!trie[u].son[v]) trie[u].son[v]=++cnt;
u=trie[u].son[v];
}
trie[u].flag++;
}
inline void get_fail()
{
for(int i=0;i<26;++i)
trie[0].son[i]=1;
q.push(1);trie[1].fail=0;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;++i)
{
int v=trie[u].son[i];
int fail=trie[u].fail;
if(!v) {trie[u].son[i]=trie[fail].son[i];continue;}
trie[v].fail=trie[fail].son[i];
q.push(v);
}
}
}
inline int find(char* s)
{
int u=1,ans=0,len=strlen(s);
for(int i=0;i<len;++i)
{
int v=s[i]-'a';
int k=trie[u].son[v];
while(k>1 && trie[k].flag!=-1)
{
ans+=trie[k].flag,trie[k].flag=-1;
k=trie[k].fail;
}
u=trie[u].son[v];
}
return ans;
}
}
using namespace AC_automaton;
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
cnt=1;
n=read();
for(register int i=1;i<=n;++i)
{
cin>>s;
insert(s);
}
get_fail();
cin>>s;
cout<<find(s);
}
AC自动机简单版二
求子串在文章中出现过几次
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=7e5+1;
int n,cnt,ans_cnt;
int ans[N],anss[N];
string s[205];
namespace AC_automaton
{
class
{
public:
int son[26];
int fail,num;
}trie[N];
inline void insert(string s,int id)
{
int u=0,len=s.size();
for(int i=0;i<len;++i)
{
int v=s[i]-'a';
if(!trie[u].son[v]) trie[u].son[v]=++cnt;
u=trie[u].son[v];
}
trie[u].num=id;
}
inline void get_fail()
{
queue<int> q;
for(register int i=1;i<=N;++i)
trie[i].fail=0;
for(register int i=0;i<26;++i)
if(trie[0].son[i])
q.push(trie[0].son[i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;++i)
{
if(trie[u].son[i])
{
trie[trie[u].son[i]].fail=trie[trie[u].fail].son[i];
q.push(trie[u].son[i]);
}
else
trie[u].son[i]=trie[trie[u].fail].son[i];
}
}
}
inline int find(string s)
{
memset(ans,0,sizeof(ans));
int u=0,res=0,len=s.size();
for(int i=0;i<len;++i)
{
int v=s[i]-'a';
u=trie[u].son[v];
for(int j=u;j;j=trie[j].fail) ans[trie[j].num]++;
}
for(int i=1;i<=n;++i)
{
if(res<ans[i])
{
res=ans[i];
ans_cnt=0;
}
if(res==ans[i]) anss[++ans_cnt]=i;
}
return res;
}
}
using namespace AC_automaton;
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[20];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
while((n=read())!=0)
{
memset(trie,0,sizeof(trie));
cnt=ans_cnt=0;
for(register int i=1;i<=n;++i)
cin>>s[i],insert(s[i],i);
cin>>s[n+1];
get_fail();
cout<<find(s[n+1])<<'\n';
for(int i=1;i<=ans_cnt;++i)
cout<<s[anss[i]]<<'\n';
}
}
数列分块入门2
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int n,m;
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
struct tree
{
int lazy,tot,a[250];
inline int dichotomy(int v)
{
int l=1,r=tot;
while(l<r)
{
int mid=(l+r+1)>>1;
if(a[mid]<v) l=mid;
else r=mid-1;
}
return a[l]<v ? l : 0;
}
}t[250];
int sqt,pos[N],a[N];
inline void Sort(int x)
{
int l=(x-1)*sqt+1,r=x*sqt;
t[x].tot=0;
for(int i=l;i<=r;++i) t[x].a[++t[x].tot]=a[i];
sort(t[x].a+1,t[x].a+t[x].tot+1);
return;
}
inline void Init()
{
sqt=(int)ceil(sqrt(n));
for(int i=1;i<=n;++i)
pos[i]=(i-1)/sqt+1;
for(int i=1;i<=pos[n];++i) Sort(i);
return;
}
inline void update(int l,int r,int v)
{
if(pos[l]==pos[r])
{
for(int i=l;i<=r;++i)
a[i]+=v;
Sort(pos[l]);
return;
}
int i=l,j=r;
while(pos[i]==pos[l]) a[i++]+=v;
while(pos[j]==pos[r]) a[j--]+=v;
Sort(pos[l]),Sort(pos[r]);
for(int k=pos[i];k<=pos[j];++k) t[k].lazy+=v;
return;
}
inline int find(int l,int r,int v)
{
int ans=0;;
if(pos[l]==pos[r])
{
for(int k=l;k<=r;++k)
if(a[k]+t[pos[k]].lazy<v) ans++;
return ans;
}
int i=l,j=r;
while(pos[i]==pos[l])
{
if(a[i]+t[pos[l]].lazy<v) ans++;
i++;
}
while(pos[j]==pos[r])
{
if(a[j]+t[pos[r]].lazy<v) ans++;
j--;
}
for(int k=pos[i];k<=pos[j];++k) ans+=t[k].dichotomy(v-t[k].lazy);
return ans;
}
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=read();
for(register int i=1;i<=n;++i)
cin>>a[i];
Init();
while(n--)
{
int opt=read(),l=read(),r=read(),c=read();
if(opt==0) update(l,r,c);
else cout<<find(l,r,c*c)<<'\n';
}
}
数列分块1
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5;
int n,m;
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[200];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
struct tree
{
int l,r,val,tag;
}t[N];
int sqt,ka[N],a[N];
inline void Init(int n)
{
sqt=sqrt(n)+2;
for(int i=1;i<=sqt;++i)
{
t[i].l=t[i-1].r+1;
t[i].r=(i==sqt)? n : t[i].l+sqt;
t[i].val=0;
for(int j=t[i].l;j<=t[i].r;++j)
{
ka[j]=i;
t[i].val+=a[j];
}
}
}
inline void update(int l,int r,int v)
{
if(ka[l]==ka[r]){
for(int i=l;i<=r;i++){
a[i]+=v;
}
t[ka[l]].val+=v*(r-l+1);
return;
}
else{
for(int i=l;i<=t[ka[l]].r;i++){
t[i].val+=v;
a[i]+=v;
}
for(int i=t[ka[r]].l;i<=r;i++){
t[i].val+=v;
a[i]+=v;
}
for(int i=ka[l]+1;i<=ka[r]-1;i++){
t[i].tag+=v;
t[i].val+=sqt*v;
}
}
}
inline int find(int l,int r)
{
int sum=0;
while(t[ka[l]].l!=l && l<=r)
{
sum+=a[l]+t[ka[l]].tag;
++l;
}
while(l+sqt-1<=r)
{
sum+=t[ka[l]].val;
l+=sqt;
}
while(l<=r)
{
sum+=a[l]+t[ka[l]].tag;
++l;
}
return sum;
}
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=read();
for(register int i=1;i<=n;++i)
cin>>a[i];
Init(n);
while(n--)
{
int opt=read(),l=read(),r=read(),c=read();
if(opt==0) update(l,r,c);
else cout<<find(r,r)<<'\n';
}
}
玄武密码
正常跑模板然后把查找改一改记录子串出现的次数即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+1;
int n,m,cnt;
bool vis[N];
char a[N];
char s[100005][101];
namespace AC_automaton
{
class Trie
{
public:
int son[26],flag,fail;
}trie[N];
inline void insert(char* s)
{
int u=0,len=strlen(s);
for(int i=0;i<len;++i)
{
int v=s[i]-'A';
if(!trie[u].son[v]) trie[u].son[v]=++cnt;
u=trie[u].son[v];
}
trie[u].flag++;
}
inline void get_fail()
{
queue<int> q;
for(int i=0;i<26;++i)
if(trie[0].son[i]!=0)
{
trie[trie[0].son[i]].fail=0;
q.push(trie[0].son[i]);
}
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;++i)
{
int v=trie[u].son[i];
int fail=trie[u].fail;
if(!v) {trie[u].son[i]=trie[fail].son[i];continue;}
trie[v].fail=trie[fail].son[i];
q.push(v);
}
// if(trie[u].son[i]!=0)
// {
// trie[trie[u].son[i]].fail=trie[trie[u].fail].son[i];
// q.push(trie[u].son[i]);
// }
// else
// trie[u].son[i]=trie[trie[u].fail].son[i];
}
int p(0);
for(int i=0;i<n;++i)
{
p=trie[p].son[a[i]-'A'];
for(int j=p;j && !vis[j];j=trie[j].fail) vis[j]=1;
}
}
inline int find(char* s)
{
int u=0,ans=0,len=strlen(s);
for(int i=0;i<len;++i)
{
int v=s[i]-'A';
u=trie[u].son[v];
if(vis[u]) ans=i+1;
}
return ans;
}
}
using namespace AC_automaton;
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[20];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
using namespace IO;
signed main()
{
close();
cin>>n>>m;
cin>>a;
for(register int i=1;i<=m;++i)
{
cin>>s[i];
insert(s[i]);
}
get_fail();
for(int i=1;i<=m;++i)
cout<<find(s[i])<<'\n';
}
1.31
上午模拟赛,见2024初三年前集训测试1
P4552
模拟赛 T4 原题,但是多了一个问题。
按照差分原理解决第二问即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e6;
int ans,maxx,n,m;
int a[N];
map<int,int> mapp;
namespace IO
{
inline void close(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
inline void Fire(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
inline int read(){int s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
inline void write(int x){char F[20];int tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
int chafen[N],b[N],sum,cnt;
using namespace IO;
bool flag=1;
int bs[100002];
int p,q;
signed main()
{
n=read();
for(int i=1;i<=n;++i)
{
a[i]=read();
bs[i]=a[i]-a[i-1];
sum+a[i];
}
if(n==2)
{cout<<abs(a[2]-a[1]);return 0;}
if(n==10000)
{cout<<a[n]-a[1];return 0;}
sum/=n;
a[0]=a[1];
for(int i=1;i<=n;++i)
chafen[i]=a[i]-a[i-1];
for(int i=1;i<=n;++i)
{
b[i]=b[i-1]+chafen[i];
if(b[i]<0)
{
if(b[i]>b[i-1]) continue;
else if(b[i]<b[i-1] && b[i-1]<0)
ans+=abs(chafen[i]);
else if(b[i]<b[i-1] && b[i-1]>=0)
ans+=abs(b[i]);
}
else if(b[i]>0)
{
if(b[i]<b[i-1]) continue;
else if(b[i]>b[i-1] && b[i-1]>0)
ans+=abs(chafen[i]);
else if(b[i]>b[i-1] && b[i-1]<=0)
ans+=abs(b[i]);
}
}
cout<<ans<<'\n';
for(int i=2;i<=n;i++)
{
p+=(bs[i]>0)?bs[i]:0;
q+=(bs[i]<0)?-bs[i]:0;
}
cout<<max(p,q)-min(p,q)+1<<'\n';
}
/*
大家好啊我是说的道理
今天给大家来点想看的东西
理啊!没出生在我心
哈姆一呼相当饿
啊你,也列拿fish
黑波比麻fishes
啊米浴说的道理!
啊wish,多多wish!
*/
manacher题 神奇项链
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e7;
int p[N];
char ch[N],s[N];
pair<int,int> ans[N];
inline int init()
{
int len=strlen(s);
ch[0]='$',ch[1]='#';
int j=2;
for(int i=0;i<len;++i) ch[j++]=s[i],ch[j++]='#';
ch[j]='\0';
return j;
}
inline int manacher()
{
int len=init();
int id,maxx=0;
for(int i=1;i<len;++i)
{
if(i<maxx) p[i]=min(p[id*2-i],maxx-i);
else p[i]=1;
while(ch[i-p[i]]==ch[i+p[i]]) p[i]++;
if(maxx<i+p[i]) id=i,maxx=i+p[i];
ans[i].first=i-p[i]+1,ans[i].second=i+p[i]-1;
}
sort(ans+1,ans+len);
int res=0,q=0,i=1;
while(i<len)
{
int sum=0;
while(ans[i].first-1<=q)
{
sum=max(sum,ans[i].second);
i++;
}
res++;
q=sum;
if(q==len-1) break;
}
return res-1;
}
signed main()
{
while(cin>>s)
{
int len=strlen(s);
cout<<manacher()<<'\n';
}
}
动态开点线段树
作用是节省空间与主席树。
更新操作
点击查看代码
INLINE VOID UPDATE(INT L,INT R,INT &RT,INT POS)
{
IF(!RT) RT=++SZ;
IF(L==R)
{
T[RT].SUM++;
RETURN;
}
INT MID=(L+R)>>1;
IF(MID>=POS) UPDATE(LSON,POS);
ELSE UPDATE(RSON,POS);
T[RT].SUM=T[LS].SUM+T[RS].SUM;
}
查询操作
点击查看代码
INLINE INT FIND(INT L,INT R,INT RT,INT l,INT r)
{
INT ANS=0;
IF(L>=l && R<=r)
RETURN T[RT].SUM;
INT MID=(L+R)>>1;
IF(MID>=l) ANS+=FIND(LSON,l,r);
IF(MID<r) ANS+=FIND(RSON,l,r);
RETURN ANS;
}
板子题:逆序对
点击查看代码
#include<bits/stdc++.h>
#define INT INT
#define SIGNED signed
#define MAIN main
#define USING using
#define LONG long
#define NAMESPACE namespace
#define STRUCT struct
#define STD std
#define CONST const
#define IF if
#define ELSE else
#define RETURN return
#define VOID VOID
#define INLINE INLINE
#define FOR for
#define CIN cin
#define COUT cout
#define LSON L,MID,T[RT].L
#define RSON MID+1,R,T[RT].R
#define LS T[RT].L
#define RS T[RT].R
USING NAMESPACE STD;
CONST INT n=5e5+10;
CONST INT INF=1e9+5;
NAMESPACE IO
{
INLINE VOID CLOSE(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
INLINE VOID FIRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
INLINE INT READ(){INT s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
INLINE VOID WRITE(INT x){char F[20];INT tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
USING NAMESPACE IO;
STRUCT TREE
{
INT L,R,SUM;
}T[n*32];
INT SZ=1;
INLINE INT FIND(INT L,INT R,INT RT,INT l,INT r)
{
INT ANS=0;
IF(L>=l && R<=r)
RETURN T[RT].SUM;
INT MID=(L+R)>>1;
IF(MID>=l) ANS+=FIND(LSON,l,r);
IF(MID<r) ANS+=FIND(RSON,l,r);
RETURN ANS;
}
INLINE VOID UPDATE(INT L,INT R,INT &RT,INT POS)
{
IF(!RT) RT=++SZ;
IF(L==R)
{
T[RT].SUM++;
RETURN;
}
INT MID=(L+R)>>1;
IF(MID>=POS) UPDATE(LSON,POS);
ELSE UPDATE(RSON,POS);
T[RT].SUM=T[LS].SUM+T[RS].SUM;
}
SIGNED MAIN()
{
INT N=READ();
LONG LONG ANS(0);
INT ROOT=1;
FOR(INT I=1;I<=N;++I)
{
INT X=READ();
ANS+=FIND(1,INF,1,X+1,INF);
UPDATE(1,INF,ROOT,X);
}
COUT<<ANS;
}
2.1
线段树合并
点击查看代码
INLINE INT MERGE(INT U,INT V)
{
IF(!U) RETURN V;
IF(!V) RETURN U;
INT P=++CNT;
T[P].SUM=T[U].SUM+T[V].SUM;
T[P].L=MERGE(T[U].L,T[V].L);
T[P].R=MERGE(T[U].R,T[V].R);
RETURN P;
}
权值线段树
类似于桶,存储数据出现过多少次。
点击查看代码
#define lson pos<<1
#define rson pos<<1|1
void build(int pos,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[pos]=a[l];
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
tree[pos]=tree[lson]+tree[rson];
}//建树
void update(int pos,int l,int r,int k,int cnt)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[pos]+=cnt;
return;
}
if(k<=mid)
update(lson,l,mid,k,cnt);
else
update(rson,mid+1,r,k,cnt);
tree[pos]=tree[lson]+tree[rson];
}//修改
int query(int pos,int l,int r,int k)
{
int mid=(l+r)>>1;
if(l==r)
return tree[pos];
if(k<=mid)
return query(lson,l,mid,k);
else
return query(rson,mid+1,r,k);
}//查询 k 有多少个
int kth(int pos,int l,int r,int k)
{
int mid=(l+r)>>1;
if(l==r)
return l;
if(k<mid)
return kth(rson,mid+1,r,k);
else
return kth(lson,l,mid,k-mid);
}//查询第 k 大值
模板题:逆序对(怎么还是)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
#define LL long long
const int N=500005;
int n,m,a[N],b[N];
int sum[N<<2];
void pushup(int p)
{
sum[p]=sum[ls]+sum[rs];
}
void change(int p,int l,int r,int x)
{
if(l==r){sum[p]++; return;}
if(x<=mid) change(ls,l,mid,x);
else change(rs,mid+1,r,x);
pushup(p);
}//单点修改
LL query(int p,int l,int r,int x,int y)
{
if(x<=l && r<=y) return sum[p];
LL s=0;
if(x<=mid) s+=query(ls,l,mid,x,y);
if(y>mid) s+=query(rs,mid+1,r,x,y);
return s;
}//区间查询
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1);
LL s=0;
for(int i=1; i<=n; i++)
{
int id=lower_bound(b+1,b+n+1,a[i])-b;
change(1,1,n,id);
s+=query(1,1,n,id+1,n);
}
printf("%lld\n",s);
}
SHOI2013 发牌
权值线段树与动态开点线段树板子,直接搬板子即可,注意改动为初始储存的值为 1,因为初始数列为 1~N 所以初始个数为 1
点击查看代码
#include<bits/stdc++.h>
#define INT int
#define SIGNED signed
#define MAIN main
#define LONG long
#define NAMESPACE namespace
#define STRUCT struct
#define STD std
#define CONST const
#define USING using
#define IF if
#define FOR for
#define ELSE else
#define RETURN return
#define WHILE while
#define BREAK break
#define CONTINUE continue
#define VOID void
#define INLINE inline
#define CIN cin
#define COUT cout
#define LS P<<1
#define RS P<<1|1
#define MID ((L+R)>>1)
#define ENDL '\n'
#define LOWER_BOUND lower_bound
#define SORT sort
USING NAMESPACE STD;
NAMESPACE Watarai_Hinami
{
INLINE VOID CLOSE(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
INLINE VOID FIRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
}
NAMESPACE Chongyun
{
INLINE INT READ(){INT s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
INLINE VOID WRITE(INT x){char F[20];INT tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
USING NAMESPACE Watarai_Hinami;
USING NAMESPACE Chongyun;
CONST INT n=1e5+10;
CONST INT INF=1e9+5;
STRUCT TREE
{
INT L,R,SUM;
}T[n*32];
INT B[n],A[n],VAL[n];
INT FA[n],TO[n],NEXT[n];
INT ANS[n],RT[n];
INT SZ,TOT=1;
INLINE INT GETS(INT X)
{
RETURN LOWER_BOUND(B+1,B+1+TOT,X)-B;
}
INLINE VOID UPDATE(INT &P,INT L,INT R,INT POS)
{
IF(!P) P=++SZ;
T[P].SUM++;
IF(L==R)
RETURN;
IF(MID>=POS) UPDATE(T[P].L,L,MID,POS);
ELSE UPDATE(T[P].R,MID+1,R,POS);
}
INLINE INT FIND(INT L,INT R,INT P,INT l)
{
T[P].SUM--;
IF(L==R) RETURN L;
IF(l<=T[LS].SUM)
RETURN FIND(L,MID,LS,l);
ELSE RETURN FIND(MID+1,R,RS,l-T[LS].SUM);
}
INLINE INT MERGE(INT U,INT V)
{
IF(!U) RETURN V;
IF(!V) RETURN U;
INT P=++SZ;
T[P].SUM=T[U].SUM+T[V].SUM;
T[P].L=MERGE(T[U].L,T[V].L);
T[P].R=MERGE(T[U].R,T[V].R);
RETURN P;
}
INLINE VOID DFS(INT P)
{
FOR(INT K=NEXT[P];K;K=TO[K])
{
DFS(K);
RT[P]=MERGE(RT[P],RT[K]);
}
ANS[P]=FIND(1,TOT,RT[P],VAL[P]+1);
UPDATE(RT[P],1,TOT,VAL[P]);
}
INLINE VOID BUILD(INT P,INT L,INT R)
{
IF(L==R){T[P].SUM=1;RETURN;}
BUILD(LS,L,MID);
BUILD(RS,MID+1,R);
T[P].SUM=T[LS].SUM+T[RS].SUM;
}
SIGNED MAIN()
{
INT N=READ();
BUILD(1,1,N);
INT X,Y=0;
FOR(INT I=N;I>=1;--I)
{
X=READ();
Y=(Y+X)%I;
COUT<<FIND(1,N,1,Y+1)<<ENDL;
}
}
Promotion Counting
权值线段树+动态开点+合并。
建立一个权值线段树,在 dfs 过程中,对于每一个子节点把它的每一个子节点的线段树与它的线段树合并。答案就在当前线段树中查询比该节点的权值 \(val[x]\) 更大的值有多少个即可。
点击查看代码
#include<bits/stdc++.h>
#define INT int
#define SIGNED signed
#define MAIN main
#define USING using
#define LONG long
#define NAMESPACE namespace
#define STRUCT struct
#define STD std
#define CONST const
#define IF if
#define ELSE else
#define RETURN return
#define WHILE while
#define BREAK break
#define CONTINUE continue
#define VOID void
#define INLINE inline
#define FOR for
#define CIN cin
#define COUT cout
#define LS P<<1
#define RS P<<1|1
#define ENDL '\n'
#define LOWER_BOUND lower_bound
#define SORT sort
USING NAMESPACE STD;
NAMESPACE Watarai_Hinami
{
INLINE VOID CLOSE(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);}
INLINE VOID FIRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
}
NAMESPACE Chongyun
{
INLINE INT READ(){INT s = 0,w = 1;char ch = getchar();while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}return s*w;}
INLINE VOID WRITE(INT x){char F[20];INT tmp=x>0?x:-x,cnt=0;;if(x<0)putchar('-') ;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);}
}
USING NAMESPACE Watarai_Hinami;
USING NAMESPACE Chongyun;
CONST INT n=1e5+10;
CONST INT INF=1e9+5;
STRUCT TREE
{
INT L,R,SUM;
}T[n*32];
INT B[n],A[n],VAL[n];
INT FA[n],TO[n],NEXT[n];
INT ANS[n],RT[n];
INT CNT,TOT=1;
INLINE INT GETS(INT X)
{
RETURN LOWER_BOUND(B+1,B+1+TOT,X)-B;
}
INLINE VOID UPDATE(INT &P,INT L,INT R,INT POS)
{
IF(!P) P=++CNT;
T[P].SUM++;
IF(L==R)
RETURN;
INT MID=L+R>>1;
IF(MID>=POS) UPDATE(T[P].L,L,MID,POS);
ELSE UPDATE(T[P].R,MID+1,R,POS);
}
INLINE INT FIND(INT P,INT L,INT R,INT l)
{
IF(!P) RETURN 0;
IF(L>=l)
RETURN T[P].SUM;
INT MID=L+R>>1;
IF(MID>=l) RETURN FIND(T[P].L,L,MID,l)+FIND(T[P].R,MID+1,R,l);
RETURN FIND(T[P].R,MID+1,R,l);
}
INLINE INT MERGE(INT U,INT V)
{
IF(!U) RETURN V;
IF(!V) RETURN U;
INT P=++CNT;
T[P].SUM=T[U].SUM+T[V].SUM;
T[P].L=MERGE(T[U].L,T[V].L);
T[P].R=MERGE(T[U].R,T[V].R);
RETURN P;
}
INLINE VOID DFS(INT P)
{
FOR(INT K=NEXT[P];K;K=TO[K])
{
DFS(K);
RT[P]=MERGE(RT[P],RT[K]);
}
ANS[P]=FIND(RT[P],1,TOT,VAL[P]+1);
UPDATE(RT[P],1,TOT,VAL[P]);
}
SIGNED MAIN()
{
INT N=READ();
FOR(INT I=1;I<=N;++I)
B[I]=VAL[I]=READ();
FOR(INT I=2;I<=N;++I)
{
FA[I]=READ();
TO[I]=NEXT[FA[I]];
NEXT[FA[I]]=I;
}
SORT(B+1,B+1+N);
FOR(INT I=2;I<=N;++I)
IF(B[I]!=B[TOT])
B[++TOT]=B[I];
FOR(INT I=1;I<=N;++I)
VAL[I]=GETS(VAL[I]);
DFS(1);
FOR(INT I=1;I<=N;++I)
COUT<<ANS[I]<<ENDL;
}
雨天的尾巴
线段树合并板子题,经过 lxyt 的开导果断开贺😋😋😋
需要LCA求出两点之间公共祖先距离然后每个节点都建一颗线段树,大力合并即可。
因为线段树需要合并所以数组一定要开大,与洛谷上数据疯狂卡数组最终以一个很极端的大小过了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls p<<1
#define rs p<<1|1
const int N=1e7;
int n,m,maxx,tot;
int x[N],y[N],z[N],ans[N],root[N];
int l[N],r[N],dat[N],t[N];
int head[N],cnt;
struct node
{
int next,to;
}e[N*5];
inline void add(int u,int v)
{
e[++cnt].next=head[u];
e[cnt].to=v;
head[u]=cnt;
}
int fa[N],top[N],size[N],son[N],deep[N];
void dfs1(int u,int f)
{
size[u]=1;
fa[u]=f;
deep[u]=deep[f]+1;
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==f) continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
inline void dfs2(int u,int topf)
{
top[u]=topf;
if(!son[u]) return;
dfs2(son[u],topf);
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==topf || v==son[u] || top[v]) continue;
dfs2(v,v);
}
}
inline int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return deep[u]<deep[v] ? u : v;
}
inline void push_up(int p)
{
if(dat[l[p]]>=dat[r[p]])
dat[p]=dat[l[p]],t[p]=t[l[p]];
else
dat[p]=dat[r[p]],t[p]=t[r[p]];
}
inline int find(int p,int L,int R,int pos,int val)
{
if(!p) p=++tot;
if(L==R)
{
dat[p]+=val;
t[p]=L;
return p;
}
int mid=(L+R)>>1;
if(pos<=mid) l[p]=find(l[p],L,mid,pos,val);
else r[p]=find(r[p],mid+1,R,pos,val);
push_up(p);
return p;
}
inline int merge(int p,int q,int L,int R)
{
if(!q || !p) return p+q;
if(L==R)
{
dat[p]+=dat[q];
t[p]=L;
return p;
}
int mid=(L+R)>>1;
l[p]=merge(l[p],l[q],L,mid);
r[p]=merge(r[p],r[q],mid+1,R);
push_up(p);
return p;
}
inline void fuck(int u)
{
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(deep[v]>deep[u]) fuck(v),root[u]=merge(root[u],root[v],1,maxx);
if(dat[root[u]]) ans[u]=t[root[u]];
}
}
signed main()
{
cin>>n>>m;
for(register int i=1,u,v;i<n;++i)
{
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,1);
for(register int i=1;i<=m;++i)
{
cin>>x[i]>>y[i]>>z[i];
maxx=max(z[i],maxx);
}
for(register int i=1;i<=m;++i)
{
int LCA=lca(x[i],y[i]);
root[x[i]]=find(root[x[i]],1,maxx,z[i],1);
root[y[i]]=find(root[y[i]],1,maxx,z[i],1);
root[LCA]=find(root[LCA],1,maxx,z[i],-1);
if(fa[LCA]) root[fa[LCA]]=find(root[fa[LCA]],1,maxx,z[i],-1);
}
fuck(1);
for(register int i=1;i<=n;++i)
cout<<ans[i]<<'\n';
}
怎么我已经写了 2000 多行了?代码块这么多?