题目大意:给出一棵树,每个结点初始均为0,要求支持以下操作:路径加等差数列,询问路径上结点权值和,回到之前的某个版本,强制在线。
调到吐血。
很明显可以看出需要树链剖分+主席树来解决,由于需要在主席树上区间修改所以标记永久化。
区间维护等差数列需要在每个结点上维护 首项 和 公差。
树链剖分时在路径上加等差数列需要讨论,细节比较多,详见代码。
(我看错题了..注意回到某个版本并不舍弃在这之间的版本)
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 150005
#define int long long
using namespace std;
typedef long long LL;
int time_clock,tot_time;
namespace Segment_Tree {
struct Node {
Node* ch[2];
int sum,a0,d,l,r,ver;
Node(Node* tmp=NULL) {
if(tmp) {
ch[0]=tmp->ch[0];
ch[1]=tmp->ch[1];
sum=tmp->sum;
a0=tmp->a0;
d=tmp->d;
l=tmp->l;
r=tmp->r;
ver=tmp->ver;
}
else {
ch[0]=ch[1]=NULL;
sum=l=r=a0=d=ver=0;
}
}
void* operator new(size_t) {
static Node *C,*mempool;
if(C==mempool) mempool=(C=new Node[1<<20])+(1<<20);
return C++;
}
}*root[N];
void init(Node*& o,int l,int r) {
o=new Node();
o->l=l, o->r=r;
if(l==r) return ;
int mid=l+r>>1;
init(o->ch[0],l,mid), init(o->ch[1],mid+1,r);
return ;
}
int query(Node* o,int l,int r) {
int tmp=(2*o->a0+o->d*(l+r-2*o->l))*(r-l+1)/2;
if(o->l==l && o->r==r) return o->sum+tmp;
int mid=o->l+o->r>>