线段树模板求卡常
查看原帖
线段树模板求卡常
912241
dream_on_screen楼主2023/7/21 09:55

虽然代码是对的,但是最慢的点正好1.00s,开O2也没用还是1.00s,要是评测姬有波动会T掉一个点

#include <iostream>
using namespace std; 
long long p;
const int memory_size=4e5;//分配内存数量 
template<class data_type>
class segment_tree
{
	private:
		template<class node_type>
		struct node
		{
			int l;
			int r;
			node_type sum;
			node_type taga;//加法延时操作
			node_type tagb;//乘法延时操作 
		};
		node<data_type> t[memory_size];
		inline void build(int id,int l,int r,data_type array[])
		{
			t[id].l=l;
			t[id].r=r;
			t[id].taga=0;
			t[id].tagb=1;
			if(l==r)
			{
				t[id].sum=array[l];
				return;
			}
			int mid=(l+r)/2;
			build(id*2,l,mid,array);
			build(id*2+1,mid+1,r,array);
			t[id].sum=t[id*2].sum+t[id*2+1].sum;
			return;
		}
		//进行id号节点的未完成操作 
		inline void push_down(int id)
		{
			//cout<<id<<"号节点标记下传\n";
			if(t[id].l!=t[id].r)
			{
				t[id*2].tagb*=t[id].tagb;
				t[id*2].taga*=t[id].tagb;
				t[id*2].taga+=t[id].taga;
				t[id*2+1].tagb*=t[id].tagb;
				t[id*2+1].taga*=t[id].tagb;
				t[id*2+1].taga+=t[id].taga;
				t[id*2].taga%=p;
				t[id*2].tagb%=p;
				t[id*2+1].taga%=p;
				t[id*2+1].tagb%=p;
			}
			t[id].sum=((t[id].sum*t[id].tagb)+t[id].taga*(t[id].r-t[id].l+1))%p;
			t[id].taga=0;
			t[id].tagb=1;
			return ;
		}
		inline void add(int id,int l,int r,data_type x)
		{
			push_down(id);
			if(t[id].l==l&&t[id].r==r)
			{
				t[id].taga+=x;
				return ;
			}
			t[id].sum+=(r-l+1)*x;
			int mid=(t[id].l+t[id].r)/2;
			bool b1=(t[id].l<=l&&l<=mid),b2=(mid+1<=r&&r<=t[id].r);
			if(b1&&!b2)
				add(id*2,l,r,x);
			else if(!b1&&b2)
				add(id*2+1,l,r,x);
			else if(b1&&b2)
			{
				add(id*2,l,mid,x);
				add(id*2+1,mid+1,r,x);
			}
			return ;
		}
		inline data_type request(int id,int l,int r)
		{
			push_down(id);
			if(t[id].l==l&&t[id].r==r)
				return t[id].sum%p;
			int mid=(t[id].l+t[id].r)/2;
			bool b1=(t[id].l<=l&&l<=mid),b2=(mid+1<=r&&r<=t[id].r);
			if(b1&&!b2)
				return request(id*2,l,r)%p;
			else if(!b1&&b2)
				return request(id*2+1,l,r)%p;
			else if(b1&&b2)
				return (request(id*2,l,mid)+request(id*2+1,mid+1,r))%p;
		}
		inline void mul(int id,int l,int r,data_type x)
		{
			push_down(id);
			if(t[id].l==l&&t[id].r==r)
			{
				t[id].tagb*=x;
				t[id].taga*=x;
				return;
			}
			t[id].sum+=request(id,l,r)*(x-1);
			int mid=(t[id].l+t[id].r)/2;
			bool b1=(t[id].l<=l&&l<=mid),b2=(mid+1<=r&&r<=t[id].r);
			if(b1&&!b2)
				mul(id*2,l,r,x);
			else if(!b1&&b2)
				mul(id*2+1,l,r,x);
			else if(b1&&b2)
			{
				mul(id*2,l,mid,x);
				mul(id*2+1,mid+1,r,x);
			}
			return ;
		}
		inline void tabs(int tab){for(int i=1;i<=tab;i++)cout<<"    ";}
		inline void print(int id,int tab)
		{
			tabs(tab);
			cout<<"第"<<id<<"号节点(左端点:"<<t[id].l<<",右端点:"<<t[id].r<<",区间和:"<<t[id].sum<<",加法延时标记:"<<t[id].taga<<",乘法延时标记:"<<t[id].tagb<<"\n";
			if(t[id].l!=t[id].r)
			{
				print(id*2,tab+1);
				print(id*2+1,tab+1);
			}
			return ;
		}
	public:
		inline void build(int length,data_type array[])
		{
			build(1,1,length,array);
		}
		inline void add(int l,int r,data_type x)
		{
			add(1,l,r,x);
		}
		inline data_type request(int l,int r)
		{
			return request(1,l,r);
		}
		inline void mul(int l,int r,data_type x)
		{
			mul(1,l,r,x);
		}
		inline void print()
		{
			print(1,0);
		}
};
segment_tree<long long> t;
long long a[100005];
int main()
{
	int n,m;
	cin>>n>>m>>p;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	t.build(n,a);
	//t.print();
	for(int i=1;i<=m;i++)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int l,r,x;
			cin>>l>>r>>x;
			t.mul(l,r,x);
		}
		else if(op==2)
		{
			int l,r,x;
			cin>>l>>r>>x;
			t.add(l,r,x);
			//t.print();
		}
		else if(op==3)
		{
			int l,r;
			cin>>l>>r;
			cout<<t.request(l,r)<<"\n";
			//t.print();
		}
	}
}

或者有没有一种可能,我是说一种可能,我的乘法操作因为每次更新区间和都要调用一次查询函数,导致总时间复杂度是O(log2n)O(log^2n) ,因为常数小数据弱所以过了,但是正确的复杂度应该少一只 loglog 呢...?

2023/7/21 09:55
加载中...