zoukankan      html  css  js  c++  java
  • Luogu P5305 [GXOI/GZOI2019]旧词

    好套路的题目,和Luogu P4211 [LNOI2014]LCA基本上就是一个题

    先考虑(sum{ile x} operatorname{depth(operatorname{lca}(i,y))})怎么做(其实就是LNOI那题)

    很容易发现此时我们两个点对的贡献为(operatorname{lca})的深度(Leftrightarrow)两点与根节点公共路径长度

    所以我们可以利用莫队+树剖,每次加一个点就是到根的一条链加(1),查询就是查某个点到根的路径和,复杂度是(O(nsqrt nlog^2 n))

    然后发现删除其实完全没有必要,因此我们离线一下就变成(O(nlog^2 n))的了

    那么考虑这题怎么做,上面的算法相当于这里的(k=1),而这个累加的(1)其实就是(( operatorname{depth}(x)+1)^1-operatorname{depth}(x)^1),是一个树上差分的过程

    因此这题每个点每次要加上的值就是(( operatorname{depth}(x)+1)^k-operatorname{depth}(x)^k),乍一看不好维护,其实仔细想一想每次加的都是定值

    那么我们线段树处理出所有对应区间的每次增加值的和,修改的时候加上这个值即可。总体复杂度(O(nlog^2 n))

    CODE

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<utility>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    typedef pair <int,int> pi;
    const int N=50005,mod=998244353;
    struct edge
    {
    	int to,nxt;
    }e[N]; int head[N],n,q,k,cnt,anc[N],dep[N],id[N],s[N],x,y,ans[N]; vector <pi> et[N];
    class FileInputOutput
    {
    	private:
    		static const int S=1<<21;
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
    		char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
    	public:
    		Tp inline void read(T& x)
    		{
    			x=0; char ch; while (!isdigit(ch=tc()));
    			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    		}
    		Tp inline void write(T x)
    		{
    			if (!x) return (void)(pc('0'),pc('
    ')); RI ptop=0;
    			while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
    		}
    		inline void Fend(void)
    		{
    			fwrite(Fout,1,Ftop,stdout);
    		}
    		#undef tc
    		#undef pc
    }F;
    inline void inc(int& x,CI y)
    {
    	if ((x+=y)>=mod) x-=mod;
    }
    inline int sum(CI a,CI b)
    {
    	int t=a+b; return t>=mod?t-mod:t;
    }
    inline int sub(CI a,CI b)
    {
    	int t=a-b; return t<0?t+mod:t;
    }
    inline int quick_pow(int x,int p,int mul=1)
    {
    	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
    }
    inline void addedge(CI x,CI y)
    {
    	e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
    }
    class Segment_Tree
    {
    	private:
    		struct segment
    		{
    			int sum,val,tag;
    		}node[N<<2];
    		#define ls now<<1
    		#define rs now<<1|1
    		#define S(x) node[x].sum
    		#define V(x) node[x].val
    		#define T(x) node[x].tag
    		inline void pushdown(CI now)
    		{
    			if (!T(now)) return; T(ls)+=T(now); inc(S(ls),1LL*T(now)*V(ls)%mod);
    			T(rs)+=T(now); inc(S(rs),1LL*T(now)*V(rs)%mod); T(now)=0;
    		}
    	public:
    		#define TN CI now=1,CI l=1,CI r=n
    		#define LS ls,l,mid
    		#define RS rs,mid+1,r
    		inline void build(TN)
    		{
    			if (l==r) return (void)(V(now)=sub(quick_pow(dep[s[l]]+1,k),quick_pow(dep[s[l]],k)));
    			int mid=l+r>>1; build(LS); build(RS); V(now)=sum(V(ls),V(rs));
    		}
    		inline int query(CI beg,CI end,TN)
    		{
    			if (beg<=l&&r<=end) return S(now); int mid=l+r>>1,ret=0; pushdown(now);
    			if (beg<=mid) inc(ret,query(beg,end,LS)); if (end>mid) inc(ret,query(beg,end,RS)); return ret;
    		}
    		inline void modify(CI beg,CI end,TN)
    		{
    			if (beg<=l&&r<=end) return ++T(now),inc(S(now),V(now)); int mid=l+r>>1; pushdown(now);
    			if (beg<=mid) modify(beg,end,LS); if (end>mid) modify(beg,end,RS); S(now)=sum(S(ls),S(rs));
    		}
    		#undef ls
    		#undef rs
    		#undef S
    		#undef V
    		#undef T
    		#undef TN
    		#undef LS
    		#undef RS
    }SEG;
    class Heavy_Light_Division
    {
    	private:
    		int son[N],top[N],size[N],idx;
    	public:
    		#define to e[i].to
    		inline void DFS1(CI now)
    		{
    			size[now]=1; for (RI i=head[now];i;i=e[i].nxt)
    			{
    				dep[to]=dep[now]+1; DFS1(to); size[now]+=size[to];
    				if (size[to]>size[son[now]]) son[now]=to;
    			}
    		}
    		inline void DFS2(CI now,CI topf=1)
    		{
    			s[id[now]=++idx]=now; top[now]=topf; if (son[now]) DFS2(son[now],topf);
    			for (RI i=head[now];i;i=e[i].nxt) if (to!=son[now]) DFS2(to,to);
    		}
    		inline int query(int nw,int ret=0)
    		{
    			while (top[nw]) inc(ret,SEG.query(id[top[nw]],id[nw])),nw=anc[top[nw]]; return ret;
    		}
    		inline void modify(int nw)
    		{
    			while (top[nw]) SEG.modify(id[top[nw]],id[nw]),nw=anc[top[nw]];
    		}
    		#undef to
    }T;
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	RI i; for (F.read(n),F.read(q),F.read(k),i=2;i<=n;++i)
    	F.read(anc[i]),addedge(anc[i],i); for (i=1;i<=q;++i)
    	F.read(x),F.read(y),et[x].push_back(make_pair(y,i));
    	for (T.DFS1(1),T.DFS2(1),SEG.build(),i=1;i<=n;++i)
    	{
    		T.modify(i); for (pi it:et[i]) ans[it.second]=T.query(it.first);
    	}
    	for (i=1;i<=q;++i) F.write(ans[i]); return F.Fend(),0;
    }
    
  • 相关阅读:
    excel VBA构造正则函数(双参数)
    excel VBA构造函数就是这么简单
    excel VBA中正则模块vbscript.regexp的用法
    excel VBA构造正则函数(单参数)
    USB 设备插拔事件处理
    MySQL 修改 root 密码命令
    函数指针
    串口编程需要注意的地方
    写开机自启动程序应该注意的一点
    C++ 中 delete 和 delete[] 的区别
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10966974.html
Copyright © 2011-2022 走看看