湘潭1247 Pair-Pair(树状数组)

分析:

给定n个二元组,求选出两个二元组(可以是同一个)组成一序列其LIS为1,2,3,4的方法数。

分别记为s1, s2, s3, s4

s1,s4对应的情形为a >= b >= c >= d, a < b < c < d,易求

长度为3时,先求得s3 + s4的值,分解为两种情况的和减去两种情况的并,min(a, b) < c < d, a < b < max(c, d),减去a < min(b, c) <= max(b, c) < d的方法数(使用二位树状数组,只考虑x[i] < y[i]),此时方法数为s3 + s4,减去s4得s3

总数为n * n,减去其他情况即为s2

若有更好的解法请指出!

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<utility>
using namespace std;
typedef long long LL;
const int N = 100008;
int C[1018];
int x[N], y[N];

inline int lowbit(int x){
    return x&-x;
}
void add(int x, int n){//将第x个数增加val,从1计数
    for(int i=x;i<=n;i+=lowbit(i)){
        C[i]++;
    }
}
int sum(int x){//求1到x的和
    int ret = 0;
    for(int i=x;i>0;i-=lowbit(i)){
        ret+=C[i];
    }
    return ret;
}
namespace bit{

int C[1008][1008];
inline int lowbit(int x){
    return x&-x;
}
void add(int x,int y,int n){
    for(int i=x;i<=n;i+=lowbit(i)){
        for(int j=y;j<=n;j+=lowbit(j)) {
            C[i][j]++;
        }
    }
}

int sum(int x,int y){
    int ret=0;
    for(int i=x;i>0;i-=lowbit(i)) {
        for(int j=y;j>0;j-=lowbit(j)) {
            ret+=C[i][j];
        }
    }
    return ret;
}
	LL solve(int n){
		LL ans = 0;
		for(int i = 1; i <= n; i++){
			if(x[i] < y[i]){
				ans += sum(x[i] - 1, y[i] - 1);
			}
		}
		return ans;
	}

}

int main(){
	int n, m;
	while(~scanf("%d %d", &n, &m)){
        memset(bit::C, 0, sizeof(bit::C));
        int tot = 0;
		for(int i = 1; i <= n; i++){
			scanf("%d %d", &x[i], &y[i]);
			if(x[i] < y[i]){
                bit::add(x[i], y[i], m);
			}
		}
		LL s1 = 0, s2 = 0, s3 = 0, s4 = 0;
		//s4
		memset(C, 0, sizeof(C));
		for(int i = 1; i<= n; i++){
			if(x[i] < y[i]){
				add(y[i], m);
			}
		}
		for(int i = 1; i <= n; i++){
			if(x[i] < y[i]){
				s4 += sum(x[i] - 1);
			}
		}
		//s3 + s4
		memset(C, 0, sizeof(C));
		for(int i = 1; i <= n; i++){
			add(min(x[i], y[i]), m);
		}
		for(int i = 1; i <= n; i++){
            if(x[i] < y[i]){
                s3 += sum(x[i] - 1);
            }
		}

		memset(C, 0, sizeof(C));
		for(int i = 1; i <= n; i++){
			add(max(x[i], y[i]), m);
		}
		for(int i = 1; i <= n; i++){
            if(x[i] < y[i]){
                s3 += n - sum(y[i]);
            }
		}

		s3 -= bit::solve(n);
		s3 -= s4;

		//s1
		memset(C, 0, sizeof(C));
		tot = 0;
		for(int i = 1; i <= n; i++){
			if(x[i] >= y[i]){
                tot++;
				add(y[i], m);
			}
		}
		for(int i = 1; i <= n; i++){
			if(x[i] >= y[i]){
				s1 += tot - sum(x[i] - 1);
			}
		}
		s2 = (LL)n * n - s1 - s3 - s4;
		printf("%I64d %I64d %I64d %I64d\n", s1, s2, s3, s4);
	}

    return 0;
}

  

时间: 2024-08-06 08:51:31

湘潭1247 Pair-Pair(树状数组)的相关文章

2016 大连网赛---Weak Pair(dfs+树状数组)

题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5877 Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a non-negative value ai is assigned.An ordered pair of nodes (u,v) is said to be weak if  (1) u

HDU 5877 Weak Pair DFS + 树状数组 + 其实不用离散化

http://acm.hdu.edu.cn/listproblem.php?vol=49 给定一颗树,然后对于每一个节点,找到它的任何一个祖先u,如果num[u] * num[v] <= k.则贡献加1 思路:主要的麻烦就是动态修改前缀和了.因为对于每个数字val.则找它祖先的话, <= k / val的数字,都是合法的.所以问题转化成求你现在dfs中保存的数字,有多少个是  <= k / val的,树状数组即可. 问题就是,数字太大了,这不适合树状数组,那么我们把每个数字离散成他们的下

HDU 5877 Weak Pair(树状数组+dfs+离散化)

http://acm.hdu.edu.cn/showproblem.php?pid=5877 题意: 给出一棵树,每个顶点都有权值,现在要你找出满足要求的点对(u,v)数,u是v的祖先并且a[u]*a[v]<=k. 思路: 转化一下,a[v]<=k/a[u],k/a[u]的最大值也就是k/a[v],也就是寻找<=k/a[v]的个数,到这儿,是不是很像树状数组? 我们只需要从根开始dfs,插入到树状数组中,并且查询即可.注意这道题目需要离散化一下. 1 #include <iostr

hdu 5877 Weak Pair dfs序+树状数组+离散化

Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a non-negative value ai is assigned.An ordered pair of no

D - Matrices with XOR property 二维树状数组+pair

Imagine A is a NxM matrix with two basic properties 1) Each element in the matrix is distinct and lies in the range of 1<=A[i][j]<=(N*M) 2) For any two cells of the matrix, (i1,j1) and (i2,j2), if (i1^j1) > (i2^j2) then A[i1][j1] > A[i2][j2] ,

树形DP+树状数组 HDU 5877 Weak Pair

1 //树形DP+树状数组 HDU 5877 Weak Pair 2 // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 3 // 这道题要离散化 4 5 #include <bits/stdc++.h> 6 using namespace std; 7 #define LL long long 8 typedef pair<int,int> pii; 9 const double inf = 12345678901234

HDU 6203 ping ping ping(dfs序+LCA+树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连通.问无法通行的点最少有多少个. 思路: 贪心思维,破坏两个点的LCA是最佳的.那么怎么判断现在在(u,v)之间的路径上有没有被破坏的点呢,如果没有的话那么此时就要破坏这个lca点.一开始我们要把询问按照u和v的lca深度从大到小排序,如果某个点需要被破坏,那么它的所有子节点都可以不再需要破坏别的点

区间的关系的计数 HDU 4638 离线+树状数组

题目大意:给你n个人,每个人都有一个id,有m个询问,每次询问一个区间[l,r],问该区间内部有多少的id是连续的(单独的也算是一个) 思路:做了那么多离线+树状数组的题目,感觉这种东西就是一个模板了,23333,反正都是定义右区间的. 这题的关键难度就是如何定义id是连续的呢.我们每次往区间里面放一个数值以后都要add(pos, 1),就是把pos~n的所有的关系都+1.然后如果说在pos之前就出现id-1,就要add(pos[id-1], -1)(同理id+1也是这样),这样子表示从pos[

HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 问你l~r之间的连续序列的gcd种类. 首先固定右端点,预处理gcd不同尽量靠右的位置(此时gcd种类不超过loga[i]种). 预处理gcd如下代码,感觉真的有点巧妙... 1 for(int i = 1; i <= n; ++i) { 2 int x = a[i], y = i; 3 for(int j = 0; j < ans[i - 1].size(); ++j) { 4 int g