暑假D14 T1 japari(树链剖分+哥德巴赫猜想)

题目描述

给定一棵树,点有点权,有三种操作:路径上的点点权加上v,路径上的点点权改成v,查询一条路径和并判断这个和是否能够分成两个质数。

对于100%的数据,1≤n,m≤100000,1≤x,y≤n,一直满足0≤Ai,S≤10000000。在增加事件中v可能为负数。 S:路径和

题解

看见题还是可以看得出是裸的树链剖分;对于两个质数分解也可以想得到哥德巴赫猜想,对于>=4的偶数都可以分成两个质数,奇数如果要分成两个质数就只可能是2+一个质数,观察到路径和是1e7,所以存下3500的以内的质数判断即可,或者直接预处理出1e7的bool数组,对于0,1,2这些小的数注意一下就好。

比较有趣的是标记的下放,其实慢慢思考也可以想到,覆盖标记会直接修改值,不管前面的+标记;所以下放顺序应该是先下放覆盖标记,再下放+标记,在下放覆盖标记时还要清空节点的+标记。

这些多想想一个可以明白,代码还是比较清晰。

#include<bits/stdc++.h>
using namespace std;

const int maxn=100005;
const int maxx=3500;
int n,m;
int a[maxn],aa[maxn];
int dep[maxn],size[maxn],fa[maxn],son[maxn];
int num,top[maxn],id[maxn];
int root,ls[maxn<<1],rs[maxn<<1],len[maxn<<1];
int sum[maxn<<1],tag[maxn<<1],cover[maxn<<1];
int cnt,prime[maxn];
bool not_prime[maxn];
vector<int>e[maxn];

template<class T>inline void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x= f ? -x : x ;
}

void init(){
    not_prime[1]=true;
    for(int i=2;i<=maxx;i++){
        if(!not_prime[i]) prime[++cnt]=i;
        for(int j=1;j<=cnt;j++){
            if(prime[j]*i>maxx) break;
            not_prime[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}

void dfs(int u){
    size[u]=1;
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(v==fa[u]) continue;
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs(v);
        size[u]+=size[v];
        if(size[son[u]]<size[v]) son[u]=v;
    }
}

void dfs(int u,int tp){
    id[u]=++num;
    aa[num]=a[u];
    top[u]=tp;
    if(!son[u]) return ;
    dfs(son[u],tp);
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(v==fa[u]||v==son[u]) continue;
        dfs(v,v);
    }
}

void update(int rt){
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}

void build(int &rt,int l,int r){
    rt=++num;
    len[rt]=r-l+1;
    cover[rt]=-1;
    if(l==r){
        sum[rt]=aa[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(ls[rt],l,mid);
    build(rs[rt],mid+1,r);
    update(rt);
}

void put_tag(int rt,int val){
    tag[rt]+=val;
    sum[rt]+=val*len[rt];
}

void put_cover(int rt,int val){
    tag[rt]=0;
    cover[rt]=val;
    sum[rt]=val*len[rt];
}

void push_down(int rt){
    if(cover[rt]!=-1){
        put_cover(ls[rt],cover[rt]);
        put_cover(rs[rt],cover[rt]);
        cover[rt]=-1;
    }
    if(tag[rt]){
        put_tag(ls[rt],tag[rt]);
        put_tag(rs[rt],tag[rt]);
        tag[rt]=0;
    }
}

void modifytag(int rt,int l,int r,int a_l,int a_r,int val){
    if(a_l<=l&&r<=a_r){
        put_tag(rt,val);
        return ;
    }
    push_down(rt);
    int mid=(l+r)>>1;
    if(a_l<=mid) modifytag(ls[rt],l,mid,a_l,a_r,val);
    if(mid<a_r) modifytag(rs[rt],mid+1,r,a_l,a_r,val);
    update(rt);
}

void modifytag(int x,int y,int val){
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        modifytag(1,1,n,id[top[y]],id[y],val);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    modifytag(1,1,n,id[x],id[y],val);
}

void modifycover(int rt,int l,int r,int a_l,int a_r,int val){
    if(a_l<=l&&r<=a_r){
        put_cover(rt,val);
        return ;
    }
    push_down(rt);
    int mid=(l+r)>>1;
    if(a_l<=mid) modifycover(ls[rt],l,mid,a_l,a_r,val);
    if(mid<a_r) modifycover(rs[rt],mid+1,r,a_l,a_r,val);
    update(rt);
}

void modifycover(int x,int y,int val){
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        modifycover(1,1,n,id[top[y]],id[y],val);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    modifycover(1,1,n,id[x],id[y],val);
}

int query(int rt,int l,int r,int a_l,int a_r){
    if(a_l<=l&&r<=a_r) return sum[rt];
    push_down(rt);
    int mid=(l+r)>>1;
    int ret=0;
    if(a_l<=mid) ret+=query(ls[rt],l,mid,a_l,a_r);
    if(mid<a_r) ret+=query(rs[rt],mid+1,r,a_l,a_r);
    return ret;
}

bool get(int x){
    if(x<=maxx) return !not_prime[x];
    for(int i=1;prime[i]*prime[i]<=x;i++)
     if(x%prime[i]==0) return false;
    return true;
}

bool check(int x){
    if(x&1){//奇数 
        if(x==1) return false;
        if(get(x-2)) return true;//x=2+质数 
        return false;
    }
    //偶数
    if(!x||x==2) return false;
    return true;//哥德巴赫猜想 
}

bool query(int x,int y){
    int ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        ret+=query(1,1,n,id[top[y]],id[y]);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ret+=query(1,1,n,id[x],id[y]);
    //printf("%d ",ret);
    return check(ret);
}

int main(){
    freopen("japari.in","r",stdin);
    freopen("japari.out","w",stdout);
    init();
//    printf("%d ",cnt);
//    for(int i=1;i<=cnt;i++) printf("%d ",prime[i]);
    read(n);read(m);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<n;i++){
        int x,y;
        read(x);read(y);
        e[x].push_back(y);
        e[y].push_back(x); 
    }
    dep[1]=1;
    dfs(1);
    dfs(1,1);
    num=0;
    build(root,1,n);
    for(int i=1;i<=m;i++){
        int opt,x,y;
        read(opt);read(x);read(y);
        if(opt==1){
            int v;read(v);
            modifytag(x,y,v);
        }
        else if(opt==2){
            int v;read(v);
            modifycover(x,y,v);
        }
        else printf("%s
",query(x,y) ? "SUGOI" : "TANOSHI");
    }
}
/*
3 4
1 2 1
2 1
3 2
2 2 1 4
1 3 3 -1
2 2 2 2
3 1 3


4 6
2 4 0 0
2 1
3 2
4 3
2 1 4 2
1 4 4 9
1 3 2 -2
2 4 2 5
3 1 4
3 4 4

*/
View Code
原文地址:https://www.cnblogs.com/sto324/p/11252913.html