Just a Hook(区间更新)

来源:互联网 发布:软件开发电脑配置 编辑:程序博客网 时间:2024/06/05 04:17
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
11021 5 25 9 3

题意:

有N段相等的金属(编号从1到n),每段金属的初始价值均为1,

之后有m个操作

每次操作更换相应区间的金属,操作1 :换成cupreous stick,价值换成1,

操作2:换成silver stick,,价值换成2

操作3:换成golden stick,价值换成3

求这n段金属的总价值

思路:

每次操作都是对连续区间做相同的操作,而且操作次数不唯一,所以要用线段树的区间更新

代码:

#include<stdio.h>#include<string.h>#define MAX 100005using namespace std;struct node{  //建立树结点    int val;    int lazy;  //延迟标记}tree[MAX*4];/* 功能:新建线段树 root:当前线段树的根结点下标 left:树组起始下标 right:数组结束下标 */ void build(int root,int left,int right){    if(left==right){        tree[root].val=1;        return;    }    int mid=(left+right)/2;    build(root*2,left,mid);    build(root*2+1,mid+1,right);    tree[root].val=tree[root*2].val+tree[root*2+1].val;}/*功能:延迟标记下一移root:当前线段树的根结点下标left:树组起始下标 right:数组结束下标*/void root_mark(int root,int left,int right){    if(tree[root].lazy){        tree[root].val=tree[root].lazy*(right-left+1);        //如果被延迟标记过并且此时需要在root的子孙中找需要更新的线段,不管找不找到既然研究到了     // 此节点就要“落实”此节点total值 ,并使延迟标记下移。         if(left!=right)            tree[root*2].lazy=tree[root*2+1].lazy=tree[root].lazy;        tree[root].lazy=0;//根结点延迟标初始化为0    }}/*功能:区间更新root:当前线段树的根结点下标[nleft,nright]:当前线段树的范围[left,right]:更新区间num:需要换成的新值*/void update(int root,int nleft,int nright,int left,int right,int num){    root_mark(root,nleft,nright);//如果根结点有延迟标记,则延迟标记下移    if(nleft>=left&&nright<=right){  //线段树区间是更新区间的子集        tree[root].val=(nright-nleft+1)*num;        tree[root].lazy=num;        return;    }    if(nleft>right||nright<left) return;//线段树区间与更新区间没交集    int mid=(nleft+nright)/2;    update(root*2,nleft,mid,left,right,num);//更新左子树    update(root*2+1,mid+1,nright,left,right,num);//更新右子树    //根据左子树和右子树的值更新根结点的值    tree[root].val=tree[root*2].val+tree[root*2+1].val;}int main(){    int T;    scanf("%d",&T);//测试样例数    int cnt=0;    while(T--){        memset(tree,0,sizeof(tree));//初始化tree        int n;       scanf("%d",&n);        build(1,1,n);        int m;        scanf("%d",&m);        int i;        for(i=0;i<m;i++){            int a,b,c; //区间【a,b】进行操作c            scanf("%d%d%d",&a,&b,&c);            update(1,1,n,a,b,c);        }        printf("Case %d: The total value of the hook is %d.\n",++cnt,tree[1].val);    }return 0;}


原创粉丝点击