Just a Hook
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 24870 Accepted Submission(s): 12411
Problem Description
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.
Now Pudge wants to do some operations on the hook.
Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:
For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.
Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.
Sample Input
Sample Output
Case 1: The total value of the hook is 24.
Source
2008 “Sunline Cup” National Invitational Contest
题目大意:给定n个数,进行q次区间更新,求这n个数的总和
解题思路:线段树,区间更新。
代码如下:
#include"iostream"
#include"cstdio"
#define ll __int64
using namespace std;
//线段树的最大节点数
const ll maxn=110000;
//线段数定义
struct Tree{
ll l,r,sum,add;
ll getmid(){ //返回线段的中点
return (l+r)>>1;
}
}tree[4*maxn];
//向上一层推
void pushup(ll x){
ll tmp=2*x;
tree[x].sum=tree[tmp].sum+tree[tmp+1].sum;
}
//向下一层推
void pushdown(ll x){
ll tmp=2*x;
tree[tmp].add=tree[x].add;
tree[tmp+1].add=tree[x].add;
tree[tmp].sum=tree[x].add*(tree[tmp].r-tree[tmp].l+1);
tree[tmp+1].sum=tree[x].add*(tree[tmp+1].r-tree[tmp+1].l+1);
tree[x].add=0;
}
//构建线段树
void Build(ll l,ll r,ll x){
tree[x].l=l;
tree[x].r=r;
tree[x].add=0;
if(tree[x].l==tree[x].r){ //叶子节点
tree[x].sum=1;
return ;
}
ll mid=tree[x].getmid();
ll tmp=2*x;
Build(l,mid,tmp); //向左子树递归
Build(mid+1,r,tmp+1); //向右子树递归
pushup(x); //在回溯时向上推
}
//区间更新
void Updata(ll l,ll r,ll x,ll c){ //所更新区间【l,r】,增加值c,当前节点x
if(tree[x].l>r||tree[x].r<l) //节点包含区间,不在更新区间内
return ;
if(l<=tree[x].l&&tree[x].r<=r){ //节点包含区间包含于更新区间
tree[x].add=c;
tree[x].sum=c*(tree[x].r-tree[x].l+1);
return ;
}
if(tree[x].add!=0)
pushdown(x); //在抵达新一轮更新区间前,将新的值向下传达
ll tmp=2*x;
Updata(l,r,tmp,c);
Updata(l,r,tmp+1,c);
pushup(x);
}
//区间查询
ll ans; //存储查询答案
void Query(ll l,ll r,ll x){ //【l,r】为当前查询区间,x为当前节点
if(tree[x].l>r||tree[x].r<l) //节点包含区间不在查询区间
return ;
if(l<=tree[x].l&&tree[x].r<=r){ //节点区间包含于查询区间
ans+=tree[x].sum;
return ;
}
ll mid=tree[x].getmid();
ll tmp=2*x;
if(r<=mid) //当前查询区间在节点的左半区间
Query(l,r,tmp);
else if(l>mid) //当前查询区间在节点的右半区间
Query(l,r,tmp+1);
else{ //查询区间分布在节点的左右区间
Query(l,mid,tmp);
Query(mid+1,r,tmp+1);
}
}
//主函数
int main(){
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++){
ll n,q;
scanf("%I64d %I64d",&n,&q);
ans=0;
Build(1,n,1);
ll x,y,c;
while(q--){
scanf("%I64d %I64d %I64d",&x,&y,&c);
Updata(x,y,1,c);
}
Query(1,n,1);
printf("Case %d: The total value of the hook is %I64d.\n",i,ans);
}
return 0;
}