题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6874
思路:思路其实就是题解那个,已经讲得很清楚了,就是有些细节要写好点,详细的可以看代码,我跑了12s,应该是分块方法不够优秀,如果能分成严格的应该能快不少
#pragma GCC optimize(2)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define pb push_back
#define lc (d<<1)
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
const int N=2e5+8;
int n,m,b[N],tot,top[1008],sz,k[N],key[N],head[N];
int num,fa[N],block[N],x,y,z,vis[N],faa[1008],dd;
unsigned w[N],val[1008],val1[1008],sd[N],val2[N],tem[1008],ds[N],pre[N];
struct as{
int l,r,d;
unsigned ss;}d[N];
struct node{
int next,c,to;}e[N<<1];
void add(int a,int b,int c)
{
e[tot].next=head[a];
e[tot].to=b;
e[tot].c=c;
head[a]=tot++;
}
vector<tuple<int,int,int>>gg[N];
bool cmp(as x,as y){
if(b[x.l]!=b[y.l])return b[x.l]<b[y.l];
if(b[x.l]&1)return x.r<y.r;
return x.r>y.r;
}
bool cmp1(as a,as b){return a.d<b.d;}
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
int dfs(int u)//这种分块方式保证了两个关键点的lca也是关键点,这对这题还是比较重要的
{
int si=1,ma=0;//ma记录他有几个儿子的子树有关键点
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==fa[u]) continue;
ds[v]=e[i].c;w[v]=w[u]+ds[v];
fa[v]=u,si+=dfs(v);
if(k[v]) ma++;//k==1表示v子树中存在关键点
}
if(si>=sz||ma>1||u==1) k[u]=key[u]=1;//如果它本身是关键点 或 有2个及以上的儿子的子树有关键点,则它是关键点
else if(ma) k[u]=1;//它的子树有关键点
return key[u]?0:si;
}//这样分块不能严格保证块的大小,因为可能很多个子树的大小都接近sz,
//但由于每次修改都只会进一颗子树,所以关系不大
void dfs1(int u)
{
if(key[u]) block[u]=++num,top[num]=u;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==fa[u]) continue;
dfs1(v);
}
int v=u;
if(key[u])
{
while(!key[fa[v]]&&fa[v]) v=fa[v],block[v]=block[u];//将路径上的点加入当前块
v=fa[v];faa[block[u]]=block[v];//构建虚树中的边
}
else if(!block[u])
{
while(!key[fa[v]]&&fa[v]) v=fa[v];
v=fa[v],block[u]=-block[v];//不在路径上的点属于它最近关键点所在块,(分开保存,所以存成负数)
//在这题其实两关键点之间的点不应该存负数,所以下面dfs的时候改了
}
}
void dfs1(int u,unsigned z,int rt,int fg)
{
if(z)
{
if(fg) val2[u]+=z;
else sd[u]=z,block[u]=dd;
}
else if(u!=rt) return;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==fa[u]||key[v]) continue;
dfs1(v,vis[v]?z+ds[v]:z,rt,fg);
}
}
int id(int u){return (block[u]<0)?-block[u]:faa[block[u]];}
void add(int u,int fg)
{
int x,y=id(u);
x=u;y=top[y];
while(x!=y&&fa[x]) vis[x]=1,x=fa[x];
dfs1(y,0,y,fg);
x=u;y=top[id(u)];
while(x!=y&&fa[x]) vis[x]=0,x=fa[x];
}
void add(int u)
{
int x=block[u],y=id(u);
FOR(i,0,num) tem[i]=0;
while(faa[y]) tem[y]=w[top[y]]-w[top[faa[y]]],val1[y]++,y=faa[y];
if(block[u]>0) tem[x]=sd[u];
if(key[u]) val1[x]++,tem[x]=w[top[x]]-w[top[faa[x]]];//这地方注意点,找bug找了半天
FOR(i,1,num) val[i]+=tem[i]+=tem[faa[i]];
if(!key[u]) add(u,1);
}
unsigned gans(int u)
{
int x=block[u],y=(x<0)?-x:faa[x];
return key[u]?val[x]:val[y]+val1[abs(x)]*sd[u]+val2[u];
}
int main()
{
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
int zz=sqrt(n);
FOR(i,1,num) val[i]=val1[i]=0;
w[n+1]=num=tot=0,sz=zz/2;
FOR(i,0,n+1) b[i]=i/zz+1,head[i]=-1,sd[i]=k[i]=key[i]=0;
FOR(i,0,n+1) gg[i].clear(),block[i]=val2[i]=0;
FOR(i,1,n-1)
{
x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
dfs(1),dfs1(1);
FOR(i,1,num) dd=i,add(top[i],0);
FOR(i,1,m) d[i].l=read(),d[i].r=read(),d[i].d=i,d[i].ss=0;
sort(d+1,d+m+1,cmp);
d[0].l=1,d[0].r=0;
int l,r,id;
FOR(i,1,m)
{
l=d[i-1].l,r=d[i-1].r;
if(l<d[i].l) gg[r].emplace_back(l,d[i].l-1,-i);
if(l>d[i].l) gg[r].emplace_back(d[i].l,l-1,i);
l=d[i].l;
if(r<d[i].r) gg[l-1].emplace_back(r+1,d[i].r,-i);
if(r>d[i].r) gg[l-1].emplace_back(d[i].r+1,r,i);
}
unsigned sum=0;
FOR(i,1,n)
{
add(i),sum+=w[i];
pre[i]=sum+w[i+1]*i-gans(i+1)*2;
for(auto it:gg[i])
{
tie(l,r,id)=it;
FOR(j,l,r)
{
if(id<0) d[-id].ss-=sum+w[j]*i-gans(j)*2;
else d[id].ss+=sum+w[j]*i-gans(j)*2;
}
}
}
l=1,r=0;
FOR(i,1,m)
{
while(l<d[i].l) d[i].ss+=pre[l-1],l++;
while(l>d[i].l) d[i].ss-=pre[l-2],l--;
while(r<d[i].r) d[i].ss+=pre[r],r++;
while(r>d[i].r) d[i].ss-=pre[r-1],r--;
}
FOR(i,1,m) d[i].ss+=d[i-1].ss;
sort(d+1,d+m+1,cmp1);
//cout<<num<<endl;
FOR(i,1,m) printf("%u\n",d[i].ss);
}
return 0;
}