刷题记录_2024寒假2/17~2/18
我都AFO了为什么还要我写题目
年前写的不计入这里
P多少多少默认洛谷
P3313 旅行
题意略,自己不会看吗
考虑对每个信仰开一个线段树,下标为dfs序,然后就是树剖板子
对于这种开一堆动态开点线段树的题目可以存每个线段树的根节点然后就只需要开一个结构体了
code:
#include<bits/stdc++.h>
#define lc t[now].ls
#define rc t[now].rs
using namespace std;
const int N=1e5+5;
int rt[N];
struct node{
int ls,rs;
int mx,sum;
}t[2000005];
int tot=100000;
int n,q,F[N],siz[N];
int son[N];
int W[N],C[N];
int id[N],top[N],dep[N];
vector<int> eg[N];
void dfs1(int now,int fa){
dep[now]=dep[fa]+1;
F[now]=fa;
siz[now]=1;
for(int i=0;i<eg[now].size();i++){
int to=eg[now][i];
if(to==fa) continue;
dfs1(to,now);
siz[now]+=siz[to];
if(siz[to]>siz[son[now]]) son[now]=to;
}
}
int cnt;
void dfs2(int now,int tp){
id[now]=++cnt;
top[now]=tp;
if(son[now]){
dfs2(son[now],tp);
}
for(int i=0;i<eg[now].size();i++){
int to=eg[now][i];
if(to==F[now] or to==son[now]) continue;
dfs2(to,to);
}
}
void pushup(int now){
t[now].sum=t[lc].sum+t[rc].sum;
t[now].mx=max(t[lc].mx,t[rc].mx);
}
int modi(int now,int l,int r,int X,int k){
if(!now) now=++tot;
if(l==r){
t[now].sum=t[now].mx=k;
return now;
}
int mid=(l+r)>>1;
if(X<=mid) t[now].ls=(modi(t[now].ls,l,mid,X,k));
else t[now].rs=(modi(t[now].rs,mid+1,r,X,k));
pushup(now);
return now;
}
int qsum(int now,int l,int r,int L,int R){
if(!now or r<L or l>R) return 0;
if(L<=l and r<=R){
return t[now].sum;
}
int mid=(l+r)>>1;
return qsum(lc,l,mid,L,R)+qsum(rc,mid+1,r,L,R);
}
int qmax(int now,int l,int r,int L,int R){
if(!now or r<L or l>R) return 0;
if(L<=l and r<=R){
return t[now].mx;
}
int mid=(l+r)>>1;
return max(qmax(lc,l,mid,L,R),qmax(rc,mid+1,r,L,R));
}
int qlisum(int x,int y){
int RT=rt[C[x]];
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=qsum(RT,1,n,id[top[x]],id[x]);
x=F[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=qsum(RT,1,n,id[x],id[y]);
return ans;
}
int qlimax(int x,int y){
int RT=rt[C[x]];
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,qmax(RT,1,n,id[top[x]],id[x]));
x=F[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=max(ans,qmax(RT,1,n,id[x],id[y]));
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=tot;i++) rt[i]=i;
for(int i=1;i<=n;i++){
cin>>W[i]>>C[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
eg[u].push_back(v);
eg[v].push_back(u);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++){
modi(rt[C[i]],1,n,id[i],W[i]);
}
for(int i=1;i<=q;i++){
string opt;
int x,y;
cin>>opt>>x>>y;
if(opt=="CC"){
modi(rt[C[x]],1,n,id[x],0);
modi(rt[(C[x]=y)],1,n,id[x],W[x]);
}
else if(opt=="CW"){
W[x]=y;
modi(rt[C[x]],1,n,id[x],W[x]);
}
else if(opt=="QS"){
cout<<qlisum(x,y)<<"\n";
}
else cout<<qlimax(x,y)<<"\n";
}
}
本人调了一个h,警戒各位搞清楚编号颜色之类的别写混了
P2486 染色
考虑题目里的问题在序列上怎么处理
我们可以线段树维护每个叶子节点的颜色动态更新,然后注意一下颜色段的维护
一个区间的颜色段数为两个儿子的颜色段数之和,但是如果左儿子的最右边的那个叶子的颜色和右儿子最左边的颜色相同要减一(画个图琢磨一下,显然)
然后树剖一下下
注意跳重链的时候如果当前重链顶和下一个重链底端颜色相同也要减一
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1e5+5;
int n,q,F[N],siz[N];
int son[N];
int C[N];
int id[N],top[N],dep[N];
vector<int> eg[N];
int tr[N<<2];
int col[N];
int tag[N<<2];
void dfs1(int now,int fa){
dep[now]=dep[fa]+1;
F[now]=fa;
siz[now]=1;
for(int i=0;i<eg[now].size();i++){
int to=eg[now][i];
if(to==fa) continue;
dfs1(to,now);
siz[now]+=siz[to];
if(siz[to]>siz[son[now]]) son[now]=to;
}
}
int cnt;
void dfs2(int now,int tp){
id[now]=++cnt;
top[now]=tp;
if(son[now]){
dfs2(son[now],tp);
}
for(int i=0;i<eg[now].size();i++){
int to=eg[now][i];
if(to==F[now] or to==son[now]) continue;
dfs2(to,to);
}
}
void pushdown(int now,int mid) {
tag[ls]=tag[rs]=col[mid]=col[mid+1]=tag[now];
tr[ls]=tr[rs]=1;
tag[now]=0;
}
void pushup(int now,int mid){
tr[now]=tr[ls]+tr[rs]-(col[mid]==col[mid+1]);
}
void modi(int now,int l,int r,int L,int R,int k){
if(l>R or r<L) return;
if(L<=l and r<=R){
col[l]=col[r]=tag[now]=k;
tr[now]=1;
return ;
}
int mid=(l+r)>>1;
if(tag[now]){
pushdown(now,mid);
}
modi(ls,l,mid,L,R,k);
modi(rs,mid+1,r,L,R,k);
pushup(now,mid);
}
int query(int now,int l,int r,int L,int R){
if(l>R or r<L) return 0;
if(L<=l and r<=R){
return tr[now];
}
int mid=(l+r)>>1;
if(tag[now]){
pushdown(now,mid);
}
int ans=0;
ans+=query(ls,l,mid,L,R);
ans+=query(rs,mid+1,r,L,R);
if(L<=mid and R>mid and col[mid]==col[mid+1]) ans--;
return ans;
}
void modli(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modi(1,1,n,id[top[x]],id[x],k);
x=F[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
modi(1,1,n,id[x],id[y],k);
}
int qli(int x,int y){
int ans=0,tx=x,ty=y;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(1,1,n,id[top[x]],id[x]);
x=F[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,id[x],id[y]);
x=tx,y=ty;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
if(col[id[top[x]]]==col[id[F[top[x]]]]) ans--;
x=F[top[x]];
}
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>C[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
eg[u].push_back(v);
eg[v].push_back(u);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++){
modi(1,1,n,id[i],id[i],C[i]);
}
for(int i=1,x,y,k;i<=q;i++) {
string c;
cin>>c>>x>>y;
if(c=="C") cin>>k,modli(x,y,k);
else cout<<qli(x, y)<<"\n";
}
}
P7735 轻重边
考虑一条边是重边的充要条件:他两边的点没被不同的修改修改过,也就是说如果把操作视为区间赋值,则两边的颜色一致
线段树维护相邻相等二元组数量,类似上一题(见代码)
树剖一下,上树,做完了
注意初始给每个点赋一个不同的点权
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=1e5+5;
int n,q,F[N],siz[N];
int son[N];
int id[N],top[N],dep[N];
vector<int> eg[N];
int tr[N<<2];
int col[N];
int tag[N<<2];
void dfs1(int now,int fa){
son[now]=0;dep[1]=1;
dep[now]=dep[fa]+1;
F[now]=fa;
siz[now]=1;
for(int i=0;i<eg[now].size();i++){
int to=eg[now][i];
if(to==fa) continue;
dfs1(to,now);
siz[now]+=siz[to];
if(siz[to]>siz[son[now]]) son[now]=to;
}
}
int cnt;
void dfs2(int now,int tp){
id[now]=++cnt;
top[now]=tp;
if(son[now]){
dfs2(son[now],tp);
}
for(int i=0;i<eg[now].size();i++){
int to=eg[now][i];
if(to==F[now] or to==son[now]) continue;
dfs2(to,to);
}
}
void pushdown(int now,int l,int r,int mid) {
tag[ls]=tag[rs]=col[mid]=col[mid+1]=tag[now];
tr[ls]=mid-l;tr[rs]=r-mid-1;
tag[now]=0;
}
void pushup(int now,int mid){
tr[now]=tr[ls]+tr[rs]+(col[mid]==col[mid+1]);
}
void modi(int now,int l,int r,int L,int R,int k){
if(l>R or r<L) return;
if(L<=l and r<=R){
col[l]=col[r]=tag[now]=k;
tr[now]=r-l;
return ;
}
int mid=(l+r)>>1;
if(tag[now]){
pushdown(now,l,r,mid);
}
modi(ls,l,mid,L,R,k);
modi(rs,mid+1,r,L,R,k);
pushup(now,mid);
}
int query(int now,int l,int r,int L,int R){
if(l>R or r<L) return 0;
if(L<=l and r<=R){
return tr[now];
}
int mid=(l+r)>>1;
if(tag[now]){
pushdown(now,l,r,mid);
}
int ans=0;
ans+=query(ls,l,mid,L,R);
ans+=query(rs,mid+1,r,L,R);
if(L<=mid and R>mid and col[mid]==col[mid+1]) ans++;
return ans;
}
void modli(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modi(1,1,n,id[top[x]],id[x],k);
x=F[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
modi(1,1,n,id[x],id[y],k);
}
int qli(int x,int y){
int ans=0,tx=x,ty=y;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(1,1,n,id[top[x]],id[x]);
x=F[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,id[x],id[y]);
x=tx,y=ty;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
if(col[id[top[x]]]==col[id[F[top[x]]]]) ans++;
x=F[top[x]];
}
return ans;
}
int T;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){cnt=0;
memset(tr,0,sizeof tr);
memset(col,0,sizeof col);
memset(tag,0,sizeof tag);
cin>>n>>q;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
eg[u].push_back(v);
eg[v].push_back(u);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++) modi(1,1,n,id[i],id[i],i);
for(int i=1,x,y;i<=q;i++) {
int c;
cin>>c>>x>>y;
if(c==1) modli(x,y,i+n);
else cout<<qli(x, y)<<"\n";
}
for(int i=1;i<=n;i++) eg[i].clear();
}
}
CF1009F Dominant Indices
第一道不是洛谷的
依据老师讲课内容这道题要用 DSU on tree,但是我拒绝)
不会dsu,找个跌来教我一下
考虑线段树合并,深度作为下下标,随便蓸一下
然后你就mle了
写一个栈垃圾回收一下,被合并过的点就没用了
AC
#include<bits/stdc++.h>
#define ls tr[now].lc
#define rs tr[now].rc
using namespace std;
int n,cnt,tot,h[1000005],rt[1000005],ans[1000005];
int st[4000005],top;
struct seg{
int lc,rc;
int maxx,maxp;
void Clear(){
lc=rc=maxx=maxp=0;
}
}tr[4000005];
vector<int> e[1000005];
int NN(){
if(top) return st[top--];
return ++tot;
}
void pushup(int now){
if(tr[ls].maxx>=tr[rs].maxx){
tr[now].maxx=tr[ls].maxx;
tr[now].maxp=tr[ls].maxp;
}
else{
tr[now].maxx=tr[rs].maxx;
tr[now].maxp=tr[rs].maxp;
}
}
void upd(int &now,int l,int r,int x){
if(!now) now=NN();
if(l==r){
tr[now].maxx++;
tr[now].maxp=l;
return;
}
int mid=(l+r)>>1;
if(x<=mid) upd(ls,l,mid,x);
else upd(rs,mid+1,r,x);
pushup(now);
}
void Merge(int &p,int q,int l,int r){
if(!p or !q){
p=p+q;
return;
}
if(l==r){
tr[p].maxx+=tr[q].maxx;
tr[q].Clear(),st[++top]=q;
return;
}
int mid=(l+r)>>1;
Merge(tr[p].lc,tr[q].lc,l,mid);
Merge(tr[p].rc,tr[q].rc,mid+1,r);
pushup(p);
tr[q].Clear(),st[++top]=q;
}
void getans(int now,int fa,int dep){
for(int i=0;i<e[now].size();i++){
int y=e[now][i];
if(y==fa) continue;
getans(y,now,dep+1);
Merge(rt[now],rt[y],1,n);
}
upd(rt[now],1,n,dep);
ans[now]=tr[rt[now]].maxp-dep;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1,x,y;i<n;i++){
cin>>x>>y;
e[y].push_back(x);
e[x].push_back(y);
}
getans(1,0,1);
for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
return 0;
}
P2894 Hotel G
写累了放松一下,暴力可过
码不给,自己ctj
P2146 软件包管理器
我们会发现这就是板子,修改分别是给根到 \(x\) 赋1和子树赋0,查询就是修改前后的全局和的差
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
#define int long long
int n,m,tim,rt,P;
int a[N],w[N],dfn[N],fa[N],siz[N],son[N],dep[N],tp[N];
vector<int> e[N];
void dfs1(int x,int ft){
siz[x]=1;
dep[x]=dep[ft]+1;
fa[x]=ft;
for(int i=0;i<e[x].size();i++){
if(e[x][i]==ft) continue;
dfs1(e[x][i],x);
siz[x]+=siz[e[x][i]];
if(!son[x] or siz[e[x][i]]>siz[son[x]]) son[x]=e[x][i];
}
}
void dfs2(int x,int top){
dfn[x]=++tim;
w[tim]=a[x];
tp[x]=top;
if(son[x]) dfs2(son[x],top);
for(int i=0;i<e[x].size();i++){
if(e[x][i]==son[x] or e[x][i]==fa[x]) continue;
dfs2(e[x][i],e[x][i]);
}
}
#define ls (p<<1)
#define rs (p<<1|1)
int len[N<<2],tr[N<<2],ad[N<<2];
void pushup(int p){
tr[p]=tr[ls]+tr[rs];
}
void pushdown(int p){
if(!ad[p]) return;
ad[ls]=ad[p];
ad[rs]=ad[p];
tr[ls]=ad[p]*len[ls];
tr[rs]=ad[p]*len[rs];
ad[p]=0;
}
void build(int p,int l,int r){
len[p]=r-l+1;
if(l==r){
tr[p]=w[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void add(int p,int l,int r,int L,int R,int k){
if(l>R or r<L) return;
if(l>=L and r<=R){
ad[p]=k;
tr[p]=k*len[p];
// pushdown(p);
return ;
}
int mid=(l+r)>>1;
pushdown(p);
add(ls,l,mid,L,R,k);
add(rs,mid+1,r,L,R,k);
pushup(p);
}
int query(int p,int l,int r,int L,int R){
if(l>R or r<L) return 0;
if(l>=L and r<=R){
return tr[p];
}
int mid=(l+r)>>1;
pushdown(p);
return query(ls,l,mid,L,R)+query(rs,mid+1,r,L,R);
}
void mtr(int x,int z){
add(1,1,n,dfn[x],dfn[x]+siz[x]-1,z);
}
int qtr(int x){
return query(1,1,n,dfn[x],dfn[x]+siz[x]-1);
}
void mli(int x,int y,int z){
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
add(1,1,n,dfn[tp[x]],dfn[x],z);
x=fa[tp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,1,n,dfn[x],dfn[y],z);
}
int qli(int x,int y){
int ans=0;
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
ans+=query(1,1,n,dfn[tp[x]],dfn[x]);
x=fa[tp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return ans+query(1,1,n,dfn[x],dfn[y]);
}
signed main(){
cin>>n;
// for(int i=1;i<=n;i++) cin>>a[i];rt=1;
for(int i=1;i<=n;i++){
int u;
cin>>u;u++;
e[u].push_back(i);
e[i].push_back(u);
}
dfs1(rt,rt);
dfs2(rt,0);
build(1,1,n);
cin>>m;
for(int i=1,op,x;i<=m;i++){
string opt;
cin>>opt>>x;
if(opt[0]=='i'){
int ans=qtr(1);
mli(1,x,1);
ans-=qtr(1);
cout<<abs(ans)<<"\n";
}
else{
int ans=qtr(1);
mtr(x,0);
ans-=qtr(1);
cout<<abs(ans)<<"\n";
}
}
}
P5496 PAM
回文自动机板子,浅学了下
#include<bits/stdc++.h>
using namespace std;
char s[2000001];
int len[2000001],n,num[2000001],fail[2000001],last,cur,pos,trie[2000001][26],tot=1;
int getf(int x,int i){
while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])x=fail[x];
return x;
}
int main(){
scanf("%s",s);
n=strlen(s);
fail[0]=1;len[1]=-1;
for(int i=0;i<n;i++){
s[i]=(s[i]+last-97)%26+97;
pos=getf(cur,i);
if(!trie[pos][s[i]-'a']){
fail[++tot]=trie[getf(fail[pos],i)][s[i]-'a'];
trie[pos][s[i]-'a']=tot;
len[tot]=len[pos]+2;
num[tot]=num[fail[tot]]+1;
}
cur=trie[pos][s[i]-'a'];
last=num[cur];
cout<<last<<" ";
}
return 0;
}

浙公网安备 33010602011771号