关于超内存
查看原帖
关于超内存
172370
fzj2007楼主2021/8/23 14:56

RT,写的点分树,但是不知道为什么超内存了......

#include<iostream>
#include<iomanip>
#include<cstring>
#include<stack>
#include<vector>
#include<string>
#include<map>
#include<cstdlib>
#include<queue>
#include<math.h>
#include<time.h>
#include<set>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x){
	x=0;
	char ch=getchar();
	bool fl=0;
	while(ch<'0'||ch>'9') fl=(fl||ch=='-'),ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+(ch^'0'),ch=getchar();
	x=fl?-x:x;
}
template<typename T>void prt(T x){
	if(x>9) prt(x/10);
	putchar(x%10+'0');
}
template<typename T>inline void put(char ch,T x){
	if(x<0) putchar('-'),x=-x;
	prt(x);
	putchar(ch);
}
#define N 150005
int n,Q,A,w[N],cnt,head[N];
long long ans=0;//存答案
bool vis[N];
struct edge{
    int v,nxt,val;
}e[N<<1];//链式前向星
struct father{
    int x,num;
    long long dis;
};
vector<father> f[N];//存一下新树
struct Son{
    int age;//年龄
    long long dis;
    inline bool operator<(const Son &b)const{
        return age<b.age;
    }
};
vector<Son> s[N][3];//每个点的3棵子树
inline void add(int u,int v,int val){
    e[++cnt]=(edge){v,head[u],val},head[u]=cnt;
}//建边
int get_sz(int x,int fa){//求子树大小
    if(vis[x]) return 0;//已经被删了
    int res=0;
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].v!=fa) res+=get_sz(e[i].v,x);//不能往回走
    return res;
}
int get_wc(int x,int fa,int sum,int &wc){//求保持复杂度意义上的重心
    if(vis[x]) return 0;//被删了
    int ms=0,now=1;//最大子树(包括父节点那一颗),当前大小
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fa) continue;
        int sz=get_wc(v,x,sum,wc);
        ms=max(ms,sz);
        now+=sz;
    }
    ms=max(ms,sum-now);//父节点那一棵
    if(ms<=sum/2) wc=x;//更新
    return now;
}
void get_dist(int x,int fa,long long dist,int wc,int k,vector<Son> &p){//查找权值
    if(vis[x]) return;
    f[x].push_back((father){wc,k,dist});//存起来
    p.push_back((Son){w[x],dist});
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fa) continue;
        get_dist(v,x,dist+(long long)e[i].val,wc,k,p);//继续往子树走
    }
}
void calc(int x){
    if(vis[x]) return;
    get_wc(x,0,get_sz(x,0),x);
    vis[x]=1;
    int id=0;
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].v;
        if(vis[v]) continue;
        vector<Son> &p=s[x][id];
        p.push_back((Son){-1,0}),p.push_back((Son){A+1,0});//哨兵
        get_dist(v,x,e[i].val,x,id,p);
        id++;//子树个数增加
        sort(p.begin(),p.end());//排序
        for(int i=0;i<p.size();i++) p[i].dis+=p[i-1].dis;//前缀和
    }
    for(int i=head[x];i;i=e[i].nxt) calc(e[i].v);
}
int query(int x,int l,int r){
    long long res=0;
    for(int k=0;k<f[x].size();k++){
        father &now=f[x][k];
        if(w[now.x]>=l&&w[now.x]<=r) res+=now.dis;//在范围内
        for(int i=0;i<3;i++){
            if(i==now.num) continue;
            vector<Son> &p=s[now.x][i];
            if(p.empty()) continue;
            int a=lower_bound(p.begin(),p.end(),(Son){l,-1})-p.begin();//找到左端点和右端点
            int b=lower_bound(p.begin(),p.end(),(Son){r+1,-1})-p.begin();
            res+=now.dis*(b-a)+p[b-1].dis-p[a-1].dis;//加上权值
        }
    }
    for(int i=0;i<3;i++){
        vector<Son> &p=s[x][i];
        if(p.empty()) continue;
        int a=lower_bound(p.begin(),p.end(),(Son){l,-1})-p.begin();
        int b=lower_bound(p.begin(),p.end(),(Son){r+1,-1})-p.begin();
        res+=p[b-1].dis-p[a-1].dis;
    }
    return res;
}
int main(){
    read(n),read(Q),read(A);
    for(int i=1;i<=n;i++) read(w[i]);
    for(int i=1,u,v,w;i<n;i++) read(u),read(v),read(w),add(u,v,w),add(v,u,w);
    calc(1);
    for(int i=1,x,l,r;i<=Q;i++){
        read(x),read(l),read(r);
        l=(l+ans)%A,r=(r+ans)%A;
        if(l>r) swap(l,r);
        put('\n',(ans=query(x,l,r)));
    }
	return 0;
}


2021/8/23 14:56
加载中...