POJ 3695 Rectangles 1w询问求20个矩阵面积并 容斥

题目链接:点击打开链接

一个详细的题解:点击打开链接

题目大意是给出若干个矩形(n <= 20) 然后m个询问(m <= 100000)

每个询问会给出一些矩形的编号,问这些矩形的面积并有多大

谈到矩形并,也许第一反应都是线段树

但是此题有一个特点,就是n非常小,m却非常大

用线段树很有可能会不行

于是换个思路,n很小,我们可以把所有的可能组合情况都考虑到,然后呢预处理出来,这样询问时就是O(1)的查询了

但是1<<20显然是远大于100000的

也就是说我们没必要把所有情况都考虑到。

只需要考虑这m个询问中的情况就可以了

于是我们先把询问中情况都读进来,用二进制存起来。

然后就是DFS,根据容斥原理

一个矩形的面积-二个矩形相交的面积+三个矩形相交的面积。。。。。。就这样

所以DFS中可以有两种分支,一种是拿这个矩形,另一种是不拿

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <vector>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
const int inf = 1e8;
const double eps = 1e-8;
const double pi = acos(-1.0);
template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) { putchar('-');x = -x; }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;

int n, m;
struct node{
	int x1, x2, y1, y2;
	int area(){return abs(x1-x2)*abs(y1-y2);}
}a[30];
int ask[100005];
int st[1<<21];
void dfs(int xa, int ya, int xb, int yb, int deep, int flag, int sta){
	if(xa >= xb || ya >= yb)return;
	if(deep == n)
	{
		if(sta){
			for(int i = 1; i <= m; i++)
				if((ask[i]|sta) == ask[i])
					st[ask[i]] += flag*(xb-xa)*(yb-ya);
		}
		return ;
	}
	dfs(xa, ya, xb, yb, deep+1, flag, sta);
	dfs(max(xa, a[deep+1].x1), max(ya, a[deep+1].y1), min(xb, a[deep+1].x2), min(yb, a[deep+1].y2), deep+1, -flag, sta|(1<<deep));
}

int main(){
	int Cas = 1;
    while(cin>>n>>m, n+m){
    	printf("Case %d:\n", Cas++);
		for(int i = 1; i <= n; i++){
			rd(a[i].x1); rd(a[i].y1); rd(a[i].x2); rd(a[i].y2);
		}
		for(int i = 1, siz, num; i <= m; i++){
			ask[i] = 0;
			rd(siz);
			while(siz-->0){rd(num); ask[i]|=1<<(num-1);}
		}
		memset(st, 0, sizeof st);
		dfs(0,0,inf,inf, 0,-1,0);
		for(int i = 1; i <= m; i++)
			printf("Query %d: %d\n", i, st[ask[i]]);
		puts("");
	}
    return 0;
}
时间: 2024-08-11 03:26:44

POJ 3695 Rectangles 1w询问求20个矩阵面积并 容斥的相关文章

POJ 3695 Rectangles (矩形并 状压+容斥定理 好题)

Rectangles Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3730   Accepted: 1082 Description You are developing a software for painting rectangles on the screen. The software supports drawing several rectangles and filling some of them w

POJ&#183;1151 Atlantis&#183;线段树求矩形面积并

题目在这:http://poj.org/problem?id=1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the is

poj 1265 Area (Pick定理+求面积)

链接:http://poj.org/problem?id=1265 Area Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4969   Accepted: 2231 Description Being well known for its highly innovative products, Merck would definitely be a good target for industrial espionag

poj 1654 Area (多边形求面积)

链接:http://poj.org/problem?id=1654 Area Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14952   Accepted: 4189 Description You are going to compute the area of a special kind of polygon. One vertex of the polygon is the origin of the orth

【POJ 1408】 Fishnet (叉积求面积)

[POJ 1408] Fishnet (叉积求面积) 一个1*1㎡的池塘 有2*n条线代表渔网 问这些网中围出来的最大面积 一个有效面积是相邻两行和相邻两列中间夹的四边形 Input为n 后面跟着四行 每行n个浮点数 每一行分别代表a,b,c,d 如图 并且保证a(i) > a(i-1) b(i) > b(i-1) c(i) > c(i-1) d(i) > d(i-1) n(n <= 30)*2+4(四个岸)条边 枚举点数就行 相邻的四个四个点枚举 找出围出的最大面积 找点用

POJ 2774 后缀数组:求最长公共子串

思路:其实很简单,就是两个字符串连接起来,中间用个特殊字符隔开,然后用后缀数组求最长公共前缀,然后不同在两个串中,并且最长的就是最长公共子串了. 注意的是:用第一个字符串来判断是不是在同一个字符中,刚开始用了第二个字符的长度来判断WA了2发才发现. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<

poj 1226 hdu 1238 Substrings 求若干字符串正串及反串的最长公共子串 2002亚洲赛天津预选题

题目:http://poj.org/problem?id=1226 http://acm.hdu.edu.cn/showproblem.php?pid=1238 其实用hash+lcp可能也可以,甚至可能写起来更快,不过我没试,我最近在练习后缀数组,所以来练手 后缀数组的典型用法之一----------------后缀数组+lcp+二分 思路:1.首先将所有的字符串每读取一个,就将其反转,作为一组,假设其下标为i到j,那么cnt[i]到cnt[j]都标记为一个数字(这个数字意思是第几个读入的字符

POJ 3177 边双连通求连通量度的问题

这道题的总体思路就是找到连通量让它能够看作一个集合,然后找这个集合的度,度数为1的连通量为k,那么需要添加(k+1)/2条边才可以保证边双连通 这里因为一个连通量中low[]大小是相同的,所以我们用ans[low[i]]++来计度数 这道题我最开始按学长的模板来写....MLE到哭了,也不知道这道题为什么这么逗,把5000的数组改成1000也能过,当然后来换了别的思路 为了防止重边的进入,开始设置了一个hash[][]二维数组来判断边是否已经存在,不额外添入 之后,我不采用二维数组,而是在get

Poj 2263 Heavy Cargo Floyd 求最大容量路

f[i][j] = max(f[i][j],min(f[i][k],f[j][k])) #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cst