首页 > 其他分享 >点分治练习题单(动态更新)

点分治练习题单(动态更新)

时间:2023-02-24 14:12:59浏览次数:54  
标签:练习题 动态 int siz 分治 tot 子树 include root

传送门

有点难,慢慢做。

1.P2634 [国家集训队]聪聪可可

比板子要简单一点,分治时寻找路径时用桶记录模数为 \(0,1,2\) 的个数,再进行 \(01\) 背包即可。

统计答案时由于两点可以互换,所以最后答案为 \((ans-n)\times 2+n\)。

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
const int N=2e4+5;
int n,root,mp[N],siz[N],tot,vis[N],t[3],p[3],ans,c[3];
struct node
{
	int to,data;
};
vector<node>a[N];
void findzx(int x,int fa)
{
	mp[x]=0;
	siz[x]=1;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i].to==fa||vis[a[x][i].to])continue;
		findzx(a[x][i].to,x);
		mp[x]=max(mp[x],siz[a[x][i].to]);
		siz[x]+=siz[a[x][i].to];
	}
	mp[x]=max(mp[x],tot-siz[x]);
	if(mp[x]<mp[root])root=x;
}
void getdis(int x,int fa,int num)
{
	num%=3;
	p[num]++;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i].to==fa||vis[a[x][i].to])continue;
		getdis(a[x][i].to,x,num+a[x][i].data);
	}
}
void clac(int x)
{
	t[0]=c[0]=1;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		p[0]=p[1]=p[2]=0;
		getdis(a[x][i].to,x,a[x][i].data);
		for(int j=0;j<3;j++)for(int k=0;k<3;k++)t[j]+=p[k]*c[((j-k)+3)%3];
		c[0]+=p[0];
		c[1]+=p[1];
		c[2]+=p[2];
	}
	ans+=t[0];
	t[0]=t[1]=t[2]=0;
	c[0]=c[1]=c[2]=0;
}
void divide(int x,int num)
{
	vis[x]=1;
	clac(x);
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		if(siz[x]>siz[a[x][i].to])tot=siz[a[x][i].to];
		else tot=num-siz[x];
		root=0;
		findzx(a[x][i].to,x);
		divide(root,tot);
	}
}
int gcd(int x,int y)
{
	if(y==0)return x;
	return gcd(y,x%y);
}
int main()
{
	int n;
	scanf("%d",&n); 
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		a[u].push_back({v,w});
		a[v].push_back({u,w});
	}
	mp[0]=1e9;
	tot=n;
	findzx(1,0);
	divide(root,n);
	ans=(ans-n)*2+n;
	int num=gcd(ans,n*n);
	printf("%d/%d",ans/num,n*n/num);
	return 0;
}

2.P2664 树上游戏

我太蒻了,这题好难……

首先进行点分治,分裂时自己分裂的子树对自己的节点可以利用深搜搜出来,如果一个颜色在此节点到根的链上第一次出现,那么对根的贡献为其子树大小,如果不是第一次出现,那么无贡献。

然后考虑子树对子树的贡献,那么先减去自己子树做的贡献,然后搜索整棵子树,对于自己到根上的所有点的贡献都赋为整棵树的大小减去这棵子树的大小,然后求解即可,最后记得回溯自己子树的贡献。

然后是点分治最重要的东东,清空数组。

对于颜色计数 \(cnt_i\),在回溯时会自动清空,总贡献是一个变量,直接情况即可,子树大小不需要清空,因为每次搜索时会赋初值 \(1\),最后是数组 \(c_i\),代表颜色 \(i\) 做出的贡献,感觉不是很好清空,那么再搜索一遍整棵子树,将节点颜色对应的 \(c_i\) 清空。

复杂度:\(O(n\times\log(n))\),废话

#include<iostream>
#include<vector>
#include<cstdio>
#define int long long
using namespace std;
const int N=1e5+5;
int n,root,mp[N],siz[N],tot,vis[N],ans[N],c[N],cnt[N],sum,nbr,t[N],lim;
vector<int>a[N];
void findzx(int x,int fa)
{
	mp[x]=0;
	siz[x]=1;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i]==fa||vis[a[x][i]])continue;
		findzx(a[x][i],x);
		mp[x]=max(mp[x],siz[a[x][i]]);
		siz[x]+=siz[a[x][i]];
	}
	mp[x]=max(mp[x],tot-siz[x]);
	if(mp[x]<mp[root])root=x;
}
void dfs(int x,int fa)
{
	cnt[t[x]]++;
	siz[x]=1;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i]]||a[x][i]==fa)continue;
		dfs(a[x][i],x);
		siz[x]+=siz[a[x][i]];
	}
	if(cnt[t[x]]==1)
	{
		c[t[x]]+=siz[x];
		sum+=siz[x];
	}
	cnt[t[x]]--;
}
void change(int x,int fa,int val)
{
	cnt[t[x]]++;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i]]||a[x][i]==fa)continue;
		change(a[x][i],x,val);
	}
	if(cnt[t[x]]==1)
	{
		c[t[x]]+=val*siz[x];
		sum+=val*siz[x];
	}
	cnt[t[x]]--;
}
void dfs2(int x,int fa)
{
	cnt[t[x]]++;
	if(cnt[t[x]]==1)
	{ 
		sum-=c[t[x]];
		lim++;
	}
	ans[x]+=lim*nbr+sum;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i]==fa||vis[a[x][i]])continue;
		dfs2(a[x][i],x);
	}
	if(cnt[t[x]]==1)
	{
		sum+=c[t[x]];
		lim--;
	}
	cnt[t[x]]--;
}
void clea(int x,int fa)
{
	cnt[t[x]]=c[t[x]]=0;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i]]||a[x][i]==fa)continue;
		clea(a[x][i],x);
	}
}
void clac(int x)
{
	dfs(x,0);
	ans[x]+=sum-c[t[x]]+siz[x];
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i]])continue;
		cnt[t[x]]++;
		
		c[t[x]]-=siz[a[x][i]];
		sum-=siz[a[x][i]];
		change(a[x][i],x,-1);
		cnt[t[x]]--;
		nbr=siz[x]-siz[a[x][i]];
		dfs2(a[x][i],x);
		cnt[t[x]]++;
		change(a[x][i],x,1);
		c[t[x]]+=siz[a[x][i]];
		sum+=siz[a[x][i]];
		cnt[t[x]]--;
	}
	sum=lim=0;
	clea(x,0);
}
void divide(int x,int num)
{
	clac(x);
	vis[x]=1;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i]])continue;
		if(siz[x]>siz[a[x][i]])tot=siz[a[x][i]];
		else tot=num-siz[x];
		root=0;
		findzx(a[x][i],x);
		divide(root,tot);
	}
}
signed main()
{
	int n;
	scanf("%lld",&n); 
	for(int i=1;i<=n;i++)scanf("%lld",&t[i]);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%lld%lld",&u,&v);
		a[u].push_back(v);
		a[v].push_back(u);
	}
	mp[0]=1e9;
	tot=n;
	findzx(1,0);
	divide(root,n);
	for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
	return 0;
}

P3714 [BJOI2017]树的难题

我太蒻了,又调了一天……

本题如果没有 \(l,r\) 的限制,就是一个裸的点分治。

现在我们加上了 \(l,r\) 的限制条件,那么我们就需要进行区间处理。

如果在范围内进行 \(01\) 背包,很明显有单调性,但是由于有排序等操作,复杂度会上升到 \(O(n\times\log_2^2(n))\),而我太菜不太会 \(\text{bfs}\) 优化,那既然复杂度都是 \(\log_2^2(n)\),为什么不用线段树呢。

对于每一个点,分裂时按照其与子节点的边的颜色进行排序,然后在每次对于一个子树有 \(k\) 条边的情况,那么另一条分支应该是之前子树中有 \((\max(1,l-k),r-k)\) 区间中的边所得到答案的最大值。

如果合并时边相同,要减去 \(c_{(i,j)}\)。

所以要维护两个线段树,一个代表与自己颜色不同,一个代表与自己颜色相同

所以大概步骤是这样的:

1、处理每一棵子树的每个深度所得到答案最大值。

2、对所有子树按颜色进行排序。

3、枚举一棵子树的深度,利用线段树求得另一棵子树合法的长度能得到答案的最大值,如果颜色相等要减去根到子节点的颜色所代表的权值。

4、更新同种颜色的线段树。

5、若这个颜色枚举完了,将同种颜色的线段树归并到不同种颜色线段树上,并清空同种颜色线段树。

然后是点分治的最重要的,清空数组。

为方便清空,在进行排序时,会将同种颜色的按深度排序。

那么子树每个深度的最大答案就可以利用深度进行清空,而线段树归并时同样深度也是最后一个树的深度。

然后其他都不是特别难,除了线段树。

线段树建树来清空肯定会 T,所以在每个节点第一次更新后,维护一个栈或队列记录这个点,最后要清空时依次弹出即可。

时间复杂度:\(O(n\times\log^2_2(n))\)

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N=2e5+5;
int n,m,l,r,t[N],mp[N],siz[N],root;
int vis[N],tot,ans=-2000000000,dep[N],c[N],tmp[N],cnt,nl,nr,k,dis[N];
struct segmentree
{
	int f[4*N];
	stack<int>s; 
	inline int ls(int x)
	{
		return x<<1;
	}
	inline int rs(int x)
	{
		return x<<1|1;
	}
	inline void pushup(int x)
	{
		if(f[x]==-2000000000)s.push(x);
		f[x]=max(f[ls(x)],f[rs(x)]);
	}
	void build(int x,int l,int r)
	{
		f[x]=-2000000000;
		if(l==r)return;
		int mid=(l+r)>>1;
		build(ls(x),l,mid);
		build(rs(x),mid+1,r);
		pushup(x);
	}
	void update(int x,int l,int r)
	{
		if(l==r)
		{
			if(f[x]==-2000000000)s.push(x); 
			f[x]=max(f[x],k);
			return;
		}
		int mid=(l+r)>>1;
		if(mid>=nl)update(ls(x),l,mid);
		else update(rs(x),mid+1,r);
		pushup(x);
	}
	int search(int x,int l,int r)
	{
		if(l>=nl&&r<=nr)return f[x];
		int mid=(l+r)>>1,num=-2000000000;
		if(mid>=nl)num=max(num,search(ls(x),l,mid));
		if(mid<nr)num=max(num,search(rs(x),mid+1,r));
		return num;
	}
	void clear()
	{
		while(!s.empty())
		{
			f[s.top()]=-2000000000;
			s.pop();
		}
	}
}t1,t2;
struct node
{
	int to,data;
};
vector<node>a[N];
int cmp(int x,int y)
{
	if(c[x]==c[y])return dep[x]<dep[y];
	return c[x]<c[y];
}
void findzx(int x,int fa)
{
	mp[x]=0;
	siz[x]=1;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to]||a[x][i].to==fa)continue;
		findzx(a[x][i].to,x);
		siz[x]+=siz[a[x][i].to];
		mp[x]=max(mp[x],siz[a[x][i].to]);
	}
	mp[x]=max(mp[x],tot-siz[x]);
	if(mp[x]<mp[root])root=x;
}
void dfs(int x,int fa)
{
	int len=a[x].size();
	dep[x]=1;
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to]||a[x][i].to==fa)continue;
		dfs(a[x][i].to,x);
		dep[x]=max(dep[x],dep[a[x][i].to]+1);
	}
}
void getdis(int x,int fa,int num,int deep,int sum)
{
	dis[deep]=max(dis[deep],sum);
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i].to==fa||vis[a[x][i].to])continue;
		int lim=sum;
		if(a[x][i].data!=num)lim+=t[a[x][i].data];
		getdis(a[x][i].to,x,a[x][i].data,deep+1,lim);
	}
}
void clac(int x)
{
	int len=a[x].size();
	cnt=0;
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		c[a[x][i].to]=a[x][i].data;
		dfs(a[x][i].to,x);
		tmp[++cnt]=a[x][i].to;
	}
	sort(tmp+1,tmp+1+cnt,cmp);
	for(int i=1;i<=cnt;i++)
	{
		dis[1]=t[c[tmp[i]]];
		getdis(tmp[i],x,c[tmp[i]],1,dis[1]);
		for(int j=1;j<=dep[tmp[i]];j++)
		{
			if(j>=l&&j<=r)ans=max(ans,dis[j]);
			nl=l-j,nr=r-j;
			if(nl<=0)nl=1;
			int num1=-2000000000,num2=-2000000000;
			if(nl<=nr)num1=t1.search(1,1,n);
			if(nl<=nr)num2=t2.search(1,1,n);
			ans=max(ans,max(num1+dis[j],num2+dis[j]-t[c[tmp[i]]]));
		}
		for(int j=1;j<=dep[tmp[i]];j++)
		{
			nl=j,k=dis[j];
			t2.update(1,1,n);
			dis[j]=-2000000000;
		}
		if(i!=cnt&&c[tmp[i]]!=c[tmp[i+1]])
		{
			for(int j=1;j<=dep[tmp[i]];j++)
			{
				nl=j,nr=j;
				k=t2.search(1,1,n);
				t1.update(1,1,n);
			}
			t2.clear();
		}
	}
	t1.clear();
	t2.clear();
}
void divide(int x,int num)
{
	vis[x]=1;
	clac(x);
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		if(siz[x]>siz[a[x][i].to])tot=siz[a[x][i].to];
		else tot=num-siz[x];
		root=0;
		findzx(a[x][i].to,x);
		divide(root,tot);
	}
}
int main()
{
	//freopen("journey1.in","r",stdin);
	scanf("%d%d%d%d",&n,&m,&l,&r);
	for(int i=1;i<=m;i++)scanf("%d",&t[i]);
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w); 
		a[u].push_back({v,w});
		a[v].push_back({u,w});
	}
	tot=n;
	mp[0]=2e9;
	t1.build(1,1,n);
	t2.build(1,1,n);
	findzx(1,0);
	for(int i=1;i<=n;i++)dis[i]=-2000000000;
	divide(root,n);
	printf("%d",ans);
	return 0;
}

P4149 [IOI2011]Race

点分治练习题。

对于每一次分裂进行一次背包,背包同样需要动态维护,然后应该就没有然后了(不会的先去看点分治模板,看懂了这个就会了)。

注意,本题节点从 \(0\) 开始,所以写(搬模板代码)时要注意些细节即可。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int N=2e5+5;
const int M=105;
const int T=1e6+5;
struct node
{
	int to,data;
};
vector<node>a[N];
int n,k,t[M],root,vis[N],siz[N],mp[N],tot,dis[N],judge[T],tmp1[N],tmp2[N],cnt,q[N],ans=1e9;
void dfs(int x,int fa)
{
	int len=a[x].size();
	siz[x]=1;
	mp[x]=0;
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to]||a[x][i].to==fa)continue;
		dfs(a[x][i].to,x);
		siz[x]+=siz[a[x][i].to];
		mp[x]=max(mp[x],siz[a[x][i].to]);
	}
	mp[x]=max(mp[x],tot-siz[x]);
	if(mp[x]<mp[root])root=x;
}
void get_dis(int x,int fa,int num,int dep)
{
	if(num>1e6)return;
	tmp1[++cnt]=num;
	tmp2[cnt]=dep;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i].to==fa||vis[a[x][i].to])continue;
		get_dis(a[x][i].to,x,num+a[x][i].data,dep+1);
	}
}
void clac(int x)
{
	int len=a[x].size();
	int cnp=0;
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		cnt=0;
		dis[a[x][i].to]=a[x][i].data;
		get_dis(a[x][i].to,x,a[x][i].data,1);
		for(int j=1;j<=cnt;j++)if(k>=tmp1[j])ans=min(ans,judge[k-tmp1[j]]+tmp2[j]);
		for(int j=1;j<=cnt;j++)
		{
			if(judge[tmp1[j]]>=1e8)q[++cnp]=tmp1[j];
			judge[tmp1[j]]=min(judge[tmp1[j]],tmp2[j]);
		}
	}
	for(int i=1;i<=cnp;i++)judge[q[i]]=1e9;
}
void solve(int x,int num)
{
	vis[x]=1;
	clac(x);
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		if(siz[x]>siz[a[x][i].to])tot=siz[a[x][i].to];
		else tot=num-siz[x];
		root=n+1;
		dfs(a[x][i].to,-1);
		solve(root,tot);
	}
}
int main()
{
	freopen("P4149_4.in","r",stdin);
	scanf("%d%d",&n,&k);
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		a[u].push_back({v,w});
		a[v].push_back({u,w});
	}
	tot=n;
	root=n+1;
	mp[n+1]=1e9;
	memset(judge,0x3f,sizeof(judge));
	judge[0]=0;
	dfs(1,-1);
	solve(root,tot);
	if(ans==1e9)ans=-1;
	printf("%d",ans);
	return 0;
}

P4178 Tree

很明显的点分治。

分治时对于子树上每一个不小于 \(k\) 的边长 \(d\),可以与之前小于等于 \(k-d\) 的边进行贡献,这个就很明显是点分治套数据结构了,这里选择树状数组。

清空树状数组时注意只能一个一个减,不能直接 memset。

其他貌似就与板子一样了,会模板的这个应该都看得懂吧……

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=4e4+5;
int n,k,root,tot,siz[N],mp[N],vis[N],ans,judge[N],tmp[N],q[N],cnt,f[N];
struct node
{
	int to,data;
};
vector<node>a[N];
void findzx(int x,int fa)
{
	siz[x]=1;
	mp[x]=0;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i].to==fa||vis[a[x][i].to])continue;
		findzx(a[x][i].to,x);
		siz[x]+=siz[a[x][i].to];
		mp[x]=max(mp[x],siz[a[x][i].to]);
	}
	mp[x]=max(mp[x],tot-siz[x]);
	if(mp[x]<mp[root])root=x;	
}
void getdis(int x,int fa,int num)
{
	if(num>k)return;
	tmp[++cnt]=num;
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(a[x][i].to==fa||vis[a[x][i].to])continue;
		getdis(a[x][i].to,x,num+a[x][i].data);
	}
}
inline int lowbit(int x)
{
	return x&(-x);
}
void update(int x,int kt)
{
	x++;
	while(x<=k+1)
	{
		f[x]+=kt;
		x+=lowbit(x);
	}
}
int search(int x)
{
	x++;
	int sum=0;
	while(x)
	{
		sum+=f[x];
		x-=lowbit(x);
	}
	return sum;
}
void clac(int x)
{
	int len=a[x].size();
	int cnp=0;
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		cnt=0;
		getdis(a[x][i].to,x,a[x][i].data);
		ans+=cnt;
		for(int i=1;i<=cnt;i++)ans+=search(k-tmp[i]);
		for(int i=1;i<=cnt;i++)update(tmp[i],1),q[++cnp]=tmp[i];
	}
	for(int i=1;i<=cnp;i++)update(q[i],-1);
}
void divide(int x,int num)
{
	vis[x]=1;
	clac(x);
	int len=a[x].size();
	for(int i=0;i<len;i++)
	{
		if(vis[a[x][i].to])continue;
		if(siz[x]>siz[a[x][i].to])tot=siz[a[x][i].to];
		else tot=num-siz[x];
		root=0;
		findzx(a[x][i].to,0);
		divide(root,tot);
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		a[u].push_back({v,w});
		a[v].push_back({u,w});
	}
	scanf("%d",&k);
	mp[0]=1e9;
	tot=n;
	findzx(1,0);
	divide(1,tot);
	printf("%d",ans);
	return 0;
}

标签:练习题,动态,int,siz,分治,tot,子树,include,root
From: https://www.cnblogs.com/gmtfff/p/17151279.html

相关文章

  • 树剖练习题题解总和(动态更新)
    这篇博客的练习题题解1、P3384【模板】轻重链剖分/树链剖分模板题,详见此#include<iostream>#include<cstdio>#include<vector>usingnamespacestd;intn,m,r,p,t[......
  • 浅谈点分治
    非常有趣的一个知识点。所谓点分治,也就是在树上进行分治的操作。分治可以处理许多问题,各种区间类问题很多都可以利用分治思想,例如线段树就是利用分治处理许多区间性问题......
  • 动态规划(DP算法)详解
    什么是动态规划:动态规划_百度百科内容太多了不作介绍,重点部分是无后效性,重叠子问题,最优子结构。问S->P1和S->P2有多少种路径数,毫无疑问可以先从S开始深搜两次,S->P1和S->......
  • Cesium 地图下钻 动态加载
    有这样一个需求:当鼠标滚轮向下滚动时,动态加载geojson数据,而向上滚动时,数据自动恢复原样。1.gif首先需要加载出全国的geojson数据,当选择某个省的时候,拾取到这个省的行政......
  • 微服务拆分治理最佳实践
    作者:京东零售徐强黄威张均杰背景部门中维护了一个老系统,功能都耦合在一个单体应用中(300+接口),表也放在同一个库中(200+表),导致系统存在很多风险和缺陷。经常出现问题:如......
  • 写一个动态规划的算法
    写一个动态规划的算法递归是从上往下的计算,递归中有大量的重复计算,以斐波那契为例动态规划是子上往下的解决问题,先解决小数据量下的结果层层类推,解决大数据规模下的问题动态......
  • JS 动态显示时间
    jsDate.prototype.format=function(fmt){varo={"y+":this.getFullYear,//年"M+":this.getMonth()+1,//月份......
  • 2022-2023-1《ICPC数据结构与算法》第一次练习题
    7-5环形解密(简)这个题直接就是取模向前移动和向后移动#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<vector>#includ......
  • 动态加载
    1、dlopen#include<dlfcn.h>void*dlopen(constchar*filename,intflags);功能:将动态库加载到内存。参数:filename:共享库路径。如果只给定文件的名字。按照动态链接器的......
  • C#中Linq查询条件动态化
    由于Linq查询主要是强类型查询,所以很难做到像sql语句一样,在执行前可以动态拼接。不过通过方法或者集合方式也可以实现一定的动态化。1.动态的or操作。可以简单的使用list......