zoukankan      html  css  js  c++  java
  • 清北学堂 清北-Day3-R2-打架 (fight)

    题目描述
    LYK有 (n) 个小朋友排成一排。第 (i) 个小朋友的战斗力是 $ a_i $,且他们的战斗力互不相同。

    战斗力高的会打败战斗力低的。

    LYK想恶搞这些小朋友们,具体地,它有 (k) 次操作。

    第i次操作会有两个参数 (l_i)(r_i) ,表示如果两个小朋友A,B的战斗力均在 ([l_i,r_i]) 这段区间中,它们的打架结果会相反。即如果一开始A能赢B,则现在变成B能赢A。当然它们的打架结果可能在后来的操作中又被反过来。

    LYK想知道,m次操作后,存在多少三元组(a,b,c),其中a能赢b,b能赢c,c能赢a。注意这里(a,b,c),(b,c,a),(c,a,b)算同一种三元组。

    输入
    第一行两个数n,k。
    第二行n个数表示 (a_i)
    接下来m行,每行两个数 (l_i,r_i)

    输出
    一个数表示答案。

    样例输入
    3 2
    1 2 3
    1 2
    2 3

    样例输出
    1

    样例解释
    进行过操作后,1能赢2,2能赢3,而3一开始就能赢1并且结果没被改变过,所以就存在1个符合条件的三元组。

    数据范围
    对于20%的数据 (n,k le 100)
    对于60%的数据 (n,k le 1000)
    对于另外10%的数据 $ k=0 $
    对于100%的数据,$ 3 le n le 10^5,0 le k le 10^5,0 le a_i,l_i,r_i le 10^9,li le ri $

    呃.......这个题......你们先看一眼代码再决定要不要继续看吧 (QwQ)
    这个题是标准的大毒瘤数据结构,在图上建线段树再从线段树上统计三元环
    这就是一句话做法......

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <vector>
    #define pii std::pair<LL,LL>
    #define mp std::make_pair
    #define ls ( rt << 1 )
    #define rs ( rt << 1 | 1 )
    #define mid ( ( l + r ) >> 1 )
    #define pushup(rt) t[rt].data = t[ls].data + t[rs].data
    #define LL long long
    #define noip2018RpINF return 0
    
    using std::vector;
    
    const int N = 1e5 + 5;
    
    LL n,k,v[N],vic,ans,res,cnt = 1;
    vector<pii>change,other;
    
    struct tree{
    	LL left,right;
    	LL data,tag;
    	LL lc,rc;
    }t[(N<<2)];
    		
    inline LL read(){
        LL v = 0,c = 1;char ch = getchar();
        while(ch < '0' || ch > '9'){
            if(ch == '-') c = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9'){
            v = v * 10 + ch - 48;
            ch = getchar();
        }
        return v * c;
    }
    
    inline void build(LL rt,LL l,LL r){
    	t[rt].left = l ; t[rt].right = r ; t[rt].tag = 0 ;//建树过程中统计节点信息 
    	if( l == r ) return ;//到达叶子节点 
    	build( ls , l , mid ) ; build( rs , mid + 1 , r );//向左右两棵子树递归 
    	pushup( rt ) ; return ;//合并子树信息 
    }
    
    inline void pushdown(LL rt){
    	LL l = t[rt].left , r = t[rt].right ;
    	if(t[rt].tag){
    		t[ls].tag ^= 1;t[rs].tag ^= 1;//标记取反 
    		t[ls].data = mid - l + 1 - t[ls].data;//左区间取反 
    		t[rs].data = r - mid - t[rs].data;//右区间取反 
    	}
    	t[rt].tag = 0;//标记回置 
    	return ;
    }
    
    inline void update(LL rt,LL ll,LL rr){
    	LL l = t[rt].left , r = t[rt].right ;//取出左右端点 
    	if(ll <= l && r <= rr){//到达的节点属于被更新区间 
    		t[rt].data = r - l + 1 - t[rt].data;//区间取反 
    		t[rt].tag ^= 1 ; return ;//打标记 
    	}
    	pushdown(rt);//下传标记 
    	if(ll <= mid) update(ls,ll,rr);
    	if(rr > mid) update(rs,ll,rr);
    	pushup(rt) ; return ;//左右递归及合并子树信息 
    }
    
    inline void query(LL rt,LL ll,LL rr,LL val){
    	LL l = t[rt].left , r = t[rt].right ;//取出左右端点 
    	if(ll <= l && r <= rr){
    		if(val == 1ll) res += t[rt].data ;//如果查询1的个数直接累加统计 
    		else res += ( r - l + 1 - t[rt].data ) ;//否则用区间长度减去1的个数 
    		return ;
    	}
    	pushdown(rt);//下传标记 
    	if(ll <= mid) query(ls,ll,rr,val);
    	if(rr > mid) query(rs,ll,rr,val);
    	return ;//左右递归及合并子树信息
    }
    			
    int main(){
    	n = read() ; k = read() ;
    	for(int i = 1 ; i <= n ; ++ i ) v[i] = read();
    	std::sort(v + 1 , v + n + 1);
    	for(int i = 1 ; i <= k ; ++ i ){
    		LL l = read(),r = read();
    		l = std::lower_bound(v + 1 , v + n + 1 ,l) - v ;
    		r = std::upper_bound(v + 1 , v + n + 1 ,r) - v - 1;
    		if( l > r ) continue;
    		change.push_back( mp( l , r ) );
    		other.push_back( mp( r , l ) ); 
    	}
    	build ( 1 , 1 , n ) ;
    	std::sort(change.begin(),change.end());
    	std::sort(other.begin(),other.end());
    	ans = (LL) ( n * ( n - 1 ) * ( n - 2 ) ) / 6;
    	for(int i = 1 , r = 0 , l = 0 ; i <= n ; ++ i ){
    		while( l < change.size() && change[l].first == i ){update( 1 , change[l].first , change[l].second ) ; ++ l ;}
    		vic = 0 ;
    		if( i != 1 ) {res = 0 ; query( 1 , 1 , i - 1 ,0) ; vic += res;}
    		if( i != n ) {res = 0 ; query( 1 , i + 1 , n ,1) ; vic += res;}
    		ans -= ( ( vic * ( vic - 1 ) ) >> 1 ) ;
    		while( r < other.size() && other[r].first == i){update( 1 , other[r].second , other[r].first ) ; ++ r ;}
    	}
    	printf("%lld
    ",ans);
    	noip2018RpINF;
    }
    
    May you return with a young heart after years of fighting.
  • 相关阅读:
    迭代器基础知识
    C语言I博客作业09
    第一周作业
    C语言1博客作业04
    C语言I博客作业08
    C语言博客作业05
    C语言I作业12—学期总结
    C语言I博客作业10
    C语言I博客作业06
    C语言I博客作业11
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/9892443.html
Copyright © 2011-2022 走看看