2022.10.14

xingke233 / 2024-11-09 / 原文

练习情况

P2787 语文1(chin1)- 理理思维

\(26\) 棵线段树,区间覆盖,区间查询。

注意大小写不敏感

Code:

#include<bits/stdc++.h>
using namespace std;
#define LL int
#define Ld long double
#define l(p,id) tree[id][p].l
#define r(p,id) tree[id][p].r
#define sum(p,id) tree[id][p].sum
#define add(p,id) tree[id][p].add
const int N = 60005,M=20005;

LL n,m,x,y,op,a[N],k;
struct Segment_tree{
    LL l,r,sum,add;
}tree[30][N*4];

inline LL readc(){
    char ch=getchar();
    while(!((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))) ch=getchar();
    if((ch>='a'&&ch<='z')) return ch-'a'+1;else return ch-'A'+1;
}

void pushdown(LL p,LL id){
    if(add(p,id)==-1) return ;
    sum(p<<1,id)=(r(p<<1,id)-l(p<<1,id)+1)*add(p,id);
    sum(p<<1|1,id)=(r(p<<1|1,id)-l(p<<1|1,id)+1)*add(p,id);
    add(p<<1,id)=add(p<<1|1,id)=add(p,id);
    add(p,id)=-1;
    return  ;
}

void build(LL p,LL l,LL r,LL id){
    l(p,id)=l,r(p,id)=r;
    add(p,id)=-1;
    sum(p,id)=0;
    if(l==r){
        if(id==a[l]) sum(p,id)=1;
        return ;
    }
    LL mid=(l(p,id)+r(p,id))>>1;
    build(p<<1,l,mid,id);
    build(p<<1|1,mid+1,r,id);
    sum(p,id)=sum(p<<1,id)+sum(p<<1|1,id);
    return ;
}

void change(LL p,LL l,LL r,LL id,LL k){
    if(add(p,id)==k) return ;
    if(l<=l(p,id)&&r(p,id)<=r){
        sum(p,id)=(r(p,id)-l(p,id)+1)*k;
        add(p,id)=k;
        return ;
    }
    pushdown(p,id);
    LL mid=(l(p,id)+r(p,id))>>1;
    if(l<=mid) change(p<<1,l,r,id,k);
    if(r>mid) change(p<<1|1,l,r,id,k);
    sum(p,id)=sum(p<<1,id)+sum(p<<1|1,id);
    return ;
}

LL query(LL p,LL l,LL r,LL id){
    if(sum(p,id)==0) return 0;
    if(l<=l(p,id)&&r(p,id)<=r)
        return sum(p,id);
    pushdown(p,id);
    LL mid=(l(p,id)+r(p,id))>>1,val=0;
    if(l<=mid) val+=query(p<<1,l,r,id);
    if(r>mid) val+=query(p<<1|1,l,r,id);
    return val;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        a[i]=readc();
    for(int i=1;i<=26;i++) build(1,1,n,i);
    for(int i=1;i<=m;i++){
        cin>>op>>x>>y;
        if(op==1){
            k=readc();
            cout<<query(1,x,y,k)<<endl;
        }else
        if(op==2){
            k=readc();
            for(int j=1;j<=26;j++)
            change(1,x,y,j,0);
            change(1,x,y,k,1);
        }else
        if(op==3){
            LL len=x;
            for(int j=1;j<=26;j++){
                LL t=query(1,x,y,j);
                change(1,x,y,j,0);
                if(t) change(1,len,len+t-1,j,1);
                len+=t;
            }
        }
    }
	return 0;
}

P5536 【XR-3】核心城市

树的直径模板

找到直径中点,以中点为根,遍历统计每个点能走多远。

\(k\) 远的为核心城市,第 \(k+1\) 远距离加 \(1\) 为答案。

Code:

树的直径


P2491 [SDOI2011] 消防

P1099 [NOIP2007 提高组] 树网的核

找出树的直径,从一个端点开始尺取,统计直径上两端到路径的最小值。

从直径上每个点搜与该点相连的树边,统计距离。

Code:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define Ld long double
const int N = 300005,M=20005;

LL n,d[N],id,st,s,sq,id1,last[N];
LL head[N],val[N*2],net[N*2],len[N*2],idx=1;
bool vis[N];

void add(LL x,LL y,LL w){
    val[++idx]=y,len[idx]=w;
    net[idx]=head[x];
    head[x]=idx;
    return ;
}

void dfs(LL x,LL fa){
    if(d[x]>st) id=x,st=d[x];
    for(int i=head[x];i;i=net[i]){
        LL v=val[i];
        if(vis[v]||v==fa) continue;
        last[v]=x,d[v]=d[x]+len[i];
        dfs(v,x);
    }
    return ;
}

int main(){
    cin>>n>>sq;
    for(int i=1;i<n;i++){
        LL u,v,w;
        cin>>u>>v>>w;
        add(u,v,w),add(v,u,w);
    }
    dfs(1,1);
    d[id]=0,last[id]=0,st=0,id1=id;
    dfs(id,id);
    LL ans=0x3f3f3f3f3f;
    LL a=id;
    for(int i=id;i;i=last[i]){
        while(last[a]&&d[i]-d[last[a]]<=sq) a=last[a];//尺取两端点
        ans=min(ans,max(d[a],d[id]-d[i]));//d[a]为到id1的距离,d[id]-d[i]为到id的距离
        vis[i]=1;
    }
    for(int i=id;i;i=last[i]){
        d[i]=0;
        dfs(i,i);//树上点到直径的距离
    }
    for(int i=1;i<=n;i++) ans=max(ans,d[i]);
    printf("%lld\n",ans);
	return 0;
}

P4408 [NOI2003] 逃学的小孩

树的直径两端必为 \(A\)、$ B$,从直径上的点开始枚举 \(C\) 即可

Code:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define Ld long double
const int N = 300005,M=20005;

LL n,d[N],id,st,s,sq,id1,last[N],m,dis[N],d1[N];
LL head[N],val[N*2],net[N*2],len[N*2],idx=1;
bool vis[N];

struct node{
    LL fa,len;
}t[N];

void add(LL x,LL y,LL w){
    val[++idx]=y,len[idx]=w;
    net[idx]=head[x];
    head[x]=idx;
    return ;
}

void dfs(LL x,LL fa){
    if(d[x]>st) id=x,st=d[x];
    for(int i=head[x];i;i=net[i]){
        LL v=val[i];
        if(vis[v]|v==fa) continue;
        t[v].fa=x,t[v].len=len[i];
        d[v]=d[x]+len[i];
        dfs(v,x);
    }
    return ;
}

void dfs1(LL x,LL fa,LL k1,LL k2){
    for(int i=head[x];i;i=net[i]){
        LL v=val[i];
        if(vis[v]|v==fa) continue;
        d1[v]=d1[x]+len[i];
        dis[v]=k1>k2?d1[v]+k2:d1[v]+k1;
        dfs1(v,x,k1,k2);
    }
    return ;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        LL u,v,w;
        cin>>u>>v>>w;
        add(u,v,w),add(v,u,w);
    }
    dfs(1,1);
    d[id]=0,t[id].fa=0,t[id].len=0,st=0,id1=id;
    dfs(id,id);
    LL ans=0;
    for(int i=id;i;i=t[i].fa){
        ans=max(ans,min(d[i],d[id]-d[i]));
        vis[i]=1;
    }
    for(int i=id;i;i=t[i].fa)
    dfs1(i,i,d[i],d[id]-d[i]);
    for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
    cout<<ans+d[id]<<endl;
	return 0;
}

P4281 [AHOI2008]紧急集合 / 聚会

两两求 \(LCA\)

若三个相同则为集合点,若有两个相同则另一个为集合点

别开 \(long\ long\)

\(ans=dep[u]+dep[v]+dep[c]-dep[lca_1]-dep[lca_2]-dep[lca_3]\)

Code:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define Ld long double
const int N = 500005,M=20005;

LL n,m,ans;
int head[N],net[N*2],val[N*2],idx=1;
int fa[N][35],dep[N];

void add(LL x,LL y){
    val[++idx]=y;
    net[idx]=head[x];
    head[x]=idx;
    return ;
}

void dfs(LL x,LL y){
    fa[x][0]=y;
    for(int i=1;i<=25;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=net[i]){
        LL v=val[i];
        if(v==y) continue;
        dep[v]=dep[x]+1;
        dfs(v,x);
    }
    return ;
}

LL LCA(LL x,LL y){
    if(dep[x]<dep[y])
    swap(x,y);
    for(int i=25;i>=0;i--)
        if(dep[fa[x][i]]>=dep[y])
            x=fa[x][i];
    if(x==y){
        ans-=dep[x];
        return x;
    }
    for(int i=25;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    ans-=dep[fa[x][0]];
    return fa[x][0];
}

int main(){
    cin>>n>>m;
    for(LL i=1,u,v;i<n;i++){
        cin>>u>>v;
        add(u,v),add(v,u);
    }
    dep[1]=1;
    dfs(1,1);
    for(LL i=1,u,v,c;i<=m;i++){
        ans=0;
        cin>>u>>v>>c;
        ans=dep[u]+dep[v]+dep[c];
        LL lca1=LCA(u,v),lca2=LCA(v,c),lca3=LCA(u,c);
        if(lca1==lca2)
        printf("%lld ",lca3);
        else
        if(lca2==lca3)
        printf("%lld ",lca1);
        else
        printf("%lld ",lca2);
        printf("%lld\n",ans);
    }
	return 0;
}